WebViewCore.cpp revision 6753735b5cf1b2396d387b9f876a11a5fd2b3c3d
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;III)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
3445bool WebViewCore::isSpellCheckEnabled(Node* node)
3446{
3447    bool isEnabled = true;
3448    if (node->isElementNode()) {
3449        WebCore::Element* element = static_cast<WebCore::Element*>(node);
3450        isEnabled = element->isSpellCheckingEnabled();
3451    }
3452    return isEnabled;
3453}
3454
3455void WebViewCore::initEditField(Node* node)
3456{
3457    String text = getInputText(node);
3458    int start = 0;
3459    int end = 0;
3460    getSelectionOffsets(node, start, end);
3461    JNIEnv* env = JSC::Bindings::getJNIEnv();
3462    AutoJObject javaObject = m_javaGlue->object(env);
3463    if (!javaObject.get())
3464        return;
3465    m_textGeneration = 0;
3466    InputType inputType = getInputType(node);
3467    Document* document = node->document();
3468    PlatformKeyboardEvent tab(AKEYCODE_TAB, 0, 0, false, false, false, false);
3469    PassRefPtr<KeyboardEvent> tabEvent =
3470            KeyboardEvent::create(tab, document->defaultView());
3471    Node* nextFocus = document->nextFocusableNode(node, tabEvent.get());
3472    bool isNextText = isTextInput(nextFocus);
3473    bool spellCheckEnabled = isSpellCheckEnabled(node);
3474    String label = requestLabel(document->frame(), node);
3475    jstring fieldText = wtfStringToJstring(env, text, true);
3476    jstring labelText = wtfStringToJstring(env, text, false);
3477    SelectText* selectText = createSelectText(focusedFrame()->selection()->selection());
3478    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_initEditField,
3479            reinterpret_cast<int>(node), fieldText, inputType,
3480            spellCheckEnabled, isNextText, labelText, start, end,
3481            reinterpret_cast<int>(selectText));
3482    checkException(env);
3483}
3484
3485void WebViewCore::popupReply(int index)
3486{
3487    if (m_popupReply) {
3488        m_popupReply->replyInt(index);
3489        Release(m_popupReply);
3490        m_popupReply = 0;
3491    }
3492}
3493
3494void WebViewCore::popupReply(const int* array, int count)
3495{
3496    if (m_popupReply) {
3497        m_popupReply->replyIntArray(array, count);
3498        Release(m_popupReply);
3499        m_popupReply = 0;
3500    }
3501}
3502
3503void WebViewCore::formDidBlur(const WebCore::Node* node)
3504{
3505    // If the blur is on a text input, keep track of the node so we can
3506    // hide the soft keyboard when the new focus is set, if it is not a
3507    // text input.
3508    if (isTextInput(node))
3509        m_blurringNodePointer = reinterpret_cast<int>(node);
3510}
3511
3512// This is a slightly modified Node::nextNodeConsideringAtomicNodes() with the
3513// extra constraint of limiting the search to inside a containing parent
3514WebCore::Node* nextNodeWithinParent(WebCore::Node* parent, WebCore::Node* start)
3515{
3516    if (!isAtomicNode(start) && start->firstChild())
3517        return start->firstChild();
3518    if (start->nextSibling())
3519        return start->nextSibling();
3520    const Node *n = start;
3521    while (n && !n->nextSibling()) {
3522        n = n->parentNode();
3523        if (n == parent)
3524            return 0;
3525    }
3526    if (n)
3527        return n->nextSibling();
3528    return 0;
3529}
3530
3531void WebViewCore::focusNodeChanged(WebCore::Node* newFocus)
3532{
3533    JNIEnv* env = JSC::Bindings::getJNIEnv();
3534    AutoJObject javaObject = m_javaGlue->object(env);
3535    if (!javaObject.get())
3536        return;
3537    if (!isTextInput(newFocus) && m_blurringNodePointer) {
3538        env->CallVoidMethod(javaObject.get(), m_javaGlue->m_formDidBlur, m_blurringNodePointer);
3539        checkException(env);
3540        m_blurringNodePointer = 0;
3541    }
3542    HitTestResult focusHitResult;
3543    focusHitResult.setInnerNode(newFocus);
3544    focusHitResult.setInnerNonSharedNode(newFocus);
3545    if (newFocus && newFocus->isLink() && newFocus->isElementNode()) {
3546        focusHitResult.setURLElement(static_cast<Element*>(newFocus));
3547        if (newFocus->hasChildNodes() && !newFocus->hasTagName(HTMLNames::imgTag)) {
3548            // Check to see if any of the children are images, and if so
3549            // set them as the innerNode and innerNonSharedNode
3550            // This will stop when it hits the first image. I'm not sure what
3551            // should be done in the case of multiple images inside one anchor...
3552            Node* nextNode = newFocus->firstChild();
3553            bool found = false;
3554            while (nextNode) {
3555                if (nextNode->hasTagName(HTMLNames::imgTag)) {
3556                    found = true;
3557                    break;
3558                }
3559                nextNode = nextNodeWithinParent(newFocus, nextNode);
3560            }
3561            if (found) {
3562                focusHitResult.setInnerNode(nextNode);
3563                focusHitResult.setInnerNonSharedNode(nextNode);
3564            }
3565        }
3566    }
3567    AndroidHitTestResult androidHitTest(this, focusHitResult);
3568    jobject jHitTestObj = androidHitTest.createJavaObject(env);
3569    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_focusNodeChanged, jHitTestObj);
3570    env->DeleteLocalRef(jHitTestObj);
3571}
3572
3573void WebViewCore::addMessageToConsole(const WTF::String& message, unsigned int lineNumber, const WTF::String& sourceID, int msgLevel) {
3574    JNIEnv* env = JSC::Bindings::getJNIEnv();
3575    AutoJObject javaObject = m_javaGlue->object(env);
3576    if (!javaObject.get())
3577        return;
3578    jstring jMessageStr = wtfStringToJstring(env, message);
3579    jstring jSourceIDStr = wtfStringToJstring(env, sourceID);
3580    env->CallVoidMethod(javaObject.get(),
3581            m_javaGlue->m_addMessageToConsole, jMessageStr, lineNumber,
3582            jSourceIDStr, msgLevel);
3583    env->DeleteLocalRef(jMessageStr);
3584    env->DeleteLocalRef(jSourceIDStr);
3585    checkException(env);
3586}
3587
3588void WebViewCore::jsAlert(const WTF::String& url, const WTF::String& text)
3589{
3590    JNIEnv* env = JSC::Bindings::getJNIEnv();
3591    AutoJObject javaObject = m_javaGlue->object(env);
3592    if (!javaObject.get())
3593        return;
3594    jstring jInputStr = wtfStringToJstring(env, text);
3595    jstring jUrlStr = wtfStringToJstring(env, url);
3596    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_jsAlert, jUrlStr, jInputStr);
3597    env->DeleteLocalRef(jInputStr);
3598    env->DeleteLocalRef(jUrlStr);
3599    checkException(env);
3600}
3601
3602bool WebViewCore::exceededDatabaseQuota(const WTF::String& url, const WTF::String& databaseIdentifier, const unsigned long long currentQuota, unsigned long long estimatedSize)
3603{
3604#if ENABLE(DATABASE)
3605    JNIEnv* env = JSC::Bindings::getJNIEnv();
3606    AutoJObject javaObject = m_javaGlue->object(env);
3607    if (!javaObject.get())
3608        return false;
3609    jstring jDatabaseIdentifierStr = wtfStringToJstring(env, databaseIdentifier);
3610    jstring jUrlStr = wtfStringToJstring(env, url);
3611    env->CallVoidMethod(javaObject.get(),
3612            m_javaGlue->m_exceededDatabaseQuota, jUrlStr,
3613            jDatabaseIdentifierStr, currentQuota, estimatedSize);
3614    env->DeleteLocalRef(jDatabaseIdentifierStr);
3615    env->DeleteLocalRef(jUrlStr);
3616    checkException(env);
3617    return true;
3618#endif
3619}
3620
3621bool WebViewCore::reachedMaxAppCacheSize(const unsigned long long spaceNeeded)
3622{
3623#if ENABLE(OFFLINE_WEB_APPLICATIONS)
3624    JNIEnv* env = JSC::Bindings::getJNIEnv();
3625    AutoJObject javaObject = m_javaGlue->object(env);
3626    if (!javaObject.get())
3627        return false;
3628    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_reachedMaxAppCacheSize, spaceNeeded);
3629    checkException(env);
3630    return true;
3631#endif
3632}
3633
3634void WebViewCore::populateVisitedLinks(WebCore::PageGroup* group)
3635{
3636    JNIEnv* env = JSC::Bindings::getJNIEnv();
3637    AutoJObject javaObject = m_javaGlue->object(env);
3638    if (!javaObject.get())
3639        return;
3640    m_groupForVisitedLinks = group;
3641    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_populateVisitedLinks);
3642    checkException(env);
3643}
3644
3645void WebViewCore::geolocationPermissionsShowPrompt(const WTF::String& origin)
3646{
3647    JNIEnv* env = JSC::Bindings::getJNIEnv();
3648    AutoJObject javaObject = m_javaGlue->object(env);
3649    if (!javaObject.get())
3650        return;
3651    jstring originString = wtfStringToJstring(env, origin);
3652    env->CallVoidMethod(javaObject.get(),
3653                        m_javaGlue->m_geolocationPermissionsShowPrompt,
3654                        originString);
3655    env->DeleteLocalRef(originString);
3656    checkException(env);
3657}
3658
3659void WebViewCore::geolocationPermissionsHidePrompt()
3660{
3661    JNIEnv* env = JSC::Bindings::getJNIEnv();
3662    AutoJObject javaObject = m_javaGlue->object(env);
3663    if (!javaObject.get())
3664        return;
3665    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_geolocationPermissionsHidePrompt);
3666    checkException(env);
3667}
3668
3669jobject WebViewCore::getDeviceMotionService()
3670{
3671    JNIEnv* env = JSC::Bindings::getJNIEnv();
3672    AutoJObject javaObject = m_javaGlue->object(env);
3673    if (!javaObject.get())
3674        return 0;
3675    jobject object = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_getDeviceMotionService);
3676    checkException(env);
3677    return object;
3678}
3679
3680jobject WebViewCore::getDeviceOrientationService()
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_getDeviceOrientationService);
3687    checkException(env);
3688    return object;
3689}
3690
3691bool WebViewCore::jsConfirm(const WTF::String& url, const WTF::String& text)
3692{
3693    JNIEnv* env = JSC::Bindings::getJNIEnv();
3694    AutoJObject javaObject = m_javaGlue->object(env);
3695    if (!javaObject.get())
3696        return false;
3697    jstring jInputStr = wtfStringToJstring(env, text);
3698    jstring jUrlStr = wtfStringToJstring(env, url);
3699    jboolean result = env->CallBooleanMethod(javaObject.get(), m_javaGlue->m_jsConfirm, jUrlStr, jInputStr);
3700    env->DeleteLocalRef(jInputStr);
3701    env->DeleteLocalRef(jUrlStr);
3702    checkException(env);
3703    return result;
3704}
3705
3706bool WebViewCore::jsPrompt(const WTF::String& url, const WTF::String& text, const WTF::String& defaultValue, WTF::String& result)
3707{
3708    JNIEnv* env = JSC::Bindings::getJNIEnv();
3709    AutoJObject javaObject = m_javaGlue->object(env);
3710    if (!javaObject.get())
3711        return false;
3712    jstring jUrlStr = wtfStringToJstring(env, url);
3713    jstring jInputStr = wtfStringToJstring(env, text);
3714    jstring jDefaultStr = wtfStringToJstring(env, defaultValue);
3715    jstring returnVal = static_cast<jstring>(env->CallObjectMethod(javaObject.get(), m_javaGlue->m_jsPrompt, jUrlStr, jInputStr, jDefaultStr));
3716    env->DeleteLocalRef(jUrlStr);
3717    env->DeleteLocalRef(jInputStr);
3718    env->DeleteLocalRef(jDefaultStr);
3719    checkException(env);
3720
3721    // If returnVal is null, it means that the user cancelled the dialog.
3722    if (!returnVal)
3723        return false;
3724
3725    result = jstringToWtfString(env, returnVal);
3726    env->DeleteLocalRef(returnVal);
3727    return true;
3728}
3729
3730bool WebViewCore::jsUnload(const WTF::String& url, const WTF::String& message)
3731{
3732    JNIEnv* env = JSC::Bindings::getJNIEnv();
3733    AutoJObject javaObject = m_javaGlue->object(env);
3734    if (!javaObject.get())
3735        return false;
3736    jstring jInputStr = wtfStringToJstring(env, message);
3737    jstring jUrlStr = wtfStringToJstring(env, url);
3738    jboolean result = env->CallBooleanMethod(javaObject.get(), m_javaGlue->m_jsUnload, jUrlStr, jInputStr);
3739    env->DeleteLocalRef(jInputStr);
3740    env->DeleteLocalRef(jUrlStr);
3741    checkException(env);
3742    return result;
3743}
3744
3745bool WebViewCore::jsInterrupt()
3746{
3747    JNIEnv* env = JSC::Bindings::getJNIEnv();
3748    AutoJObject javaObject = m_javaGlue->object(env);
3749    if (!javaObject.get())
3750        return false;
3751    jboolean result = env->CallBooleanMethod(javaObject.get(), m_javaGlue->m_jsInterrupt);
3752    checkException(env);
3753    return result;
3754}
3755
3756AutoJObject
3757WebViewCore::getJavaObject()
3758{
3759    return m_javaGlue->object(JSC::Bindings::getJNIEnv());
3760}
3761
3762jobject
3763WebViewCore::getWebViewJavaObject()
3764{
3765    JNIEnv* env = JSC::Bindings::getJNIEnv();
3766    AutoJObject javaObject = m_javaGlue->object(env);
3767    if (!javaObject.get())
3768        return 0;
3769    return env->GetObjectField(javaObject.get(), gWebViewCoreFields.m_webView);
3770}
3771
3772RenderTextControl* WebViewCore::toRenderTextControl(Node* node)
3773{
3774    RenderTextControl* rtc = 0;
3775    RenderObject* renderer = node->renderer();
3776    if (renderer && renderer->isTextControl()) {
3777        rtc = WebCore::toRenderTextControl(renderer);
3778    }
3779    return rtc;
3780}
3781
3782void WebViewCore::getSelectionOffsets(Node* node, int& start, int& end)
3783{
3784    RenderTextControl* rtc = toRenderTextControl(node);
3785    if (rtc) {
3786        start = rtc->selectionStart();
3787        end = rtc->selectionEnd();
3788    } else {
3789        // It must be content editable field.
3790        Document* document = node->document();
3791        Frame* frame = document->frame();
3792        SelectionController* selector = frame->selection();
3793        Position selectionStart = selector->start();
3794        Position selectionEnd = selector->end();
3795        Position startOfNode = firstPositionInNode(node);
3796        RefPtr<Range> startRange = Range::create(document, startOfNode,
3797                selectionStart);
3798        start = TextIterator::rangeLength(startRange.get(), true);
3799        RefPtr<Range> endRange = Range::create(document, startOfNode,
3800                selectionEnd);
3801        end = TextIterator::rangeLength(endRange.get(), true);
3802    }
3803}
3804
3805String WebViewCore::getInputText(Node* node)
3806{
3807    String text;
3808    WebCore::RenderTextControl* renderText = toRenderTextControl(node);
3809    if (renderText)
3810        text = renderText->text();
3811    else {
3812        // It must be content editable field.
3813        Position inNode(node, 0);
3814        Position start = firstPositionInNode(node);
3815        Position end = lastPositionInNode(node);
3816        VisibleSelection allEditableText(start, end);
3817        text = allEditableText.firstRange()->text();
3818    }
3819    return text;
3820}
3821
3822void WebViewCore::updateTextSelection()
3823{
3824    JNIEnv* env = JSC::Bindings::getJNIEnv();
3825    AutoJObject javaObject = m_javaGlue->object(env);
3826    if (!javaObject.get())
3827        return;
3828    VisibleSelection selection = focusedFrame()->selection()->selection();
3829    int start = 0;
3830    int end = 0;
3831    if (selection.isCaretOrRange())
3832        getSelectionOffsets(selection.start().anchorNode(), start, end);
3833    SelectText* selectText = createSelectText(selection);
3834    env->CallVoidMethod(javaObject.get(),
3835            m_javaGlue->m_updateTextSelection, reinterpret_cast<int>(currentFocus()),
3836            start, end, m_textGeneration, reinterpret_cast<int>(selectText));
3837    checkException(env);
3838}
3839
3840void WebViewCore::updateTextfield(WebCore::Node* ptr, bool changeToPassword,
3841        const WTF::String& text)
3842{
3843    JNIEnv* env = JSC::Bindings::getJNIEnv();
3844    AutoJObject javaObject = m_javaGlue->object(env);
3845    if (!javaObject.get())
3846        return;
3847    if (m_blockTextfieldUpdates)
3848        return;
3849    if (changeToPassword) {
3850        env->CallVoidMethod(javaObject.get(), m_javaGlue->m_updateTextfield,
3851                (int) ptr, true, 0, m_textGeneration);
3852        checkException(env);
3853        return;
3854    }
3855    jstring string = wtfStringToJstring(env, text);
3856    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_updateTextfield,
3857            (int) ptr, false, string, m_textGeneration);
3858    env->DeleteLocalRef(string);
3859    checkException(env);
3860}
3861
3862void WebViewCore::clearTextEntry()
3863{
3864    JNIEnv* env = JSC::Bindings::getJNIEnv();
3865    AutoJObject javaObject = m_javaGlue->object(env);
3866    if (!javaObject.get())
3867        return;
3868    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_clearTextEntry);
3869}
3870
3871void WebViewCore::setBackgroundColor(SkColor c)
3872{
3873    WebCore::FrameView* view = m_mainFrame->view();
3874    if (!view)
3875        return;
3876
3877    // need (int) cast to find the right constructor
3878    WebCore::Color bcolor((int)SkColorGetR(c), (int)SkColorGetG(c),
3879                          (int)SkColorGetB(c), (int)SkColorGetA(c));
3880    view->setBaseBackgroundColor(bcolor);
3881
3882    // Background color of 0 indicates we want a transparent background
3883    if (c == 0)
3884        view->setTransparent(true);
3885}
3886
3887jclass WebViewCore::getPluginClass(const WTF::String& libName, const char* className)
3888{
3889    JNIEnv* env = JSC::Bindings::getJNIEnv();
3890    AutoJObject javaObject = m_javaGlue->object(env);
3891    if (!javaObject.get())
3892        return 0;
3893
3894    jstring libString = wtfStringToJstring(env, libName);
3895    jstring classString = env->NewStringUTF(className);
3896    jobject pluginClass = env->CallObjectMethod(javaObject.get(),
3897                                           m_javaGlue->m_getPluginClass,
3898                                           libString, classString);
3899    checkException(env);
3900
3901    // cleanup unneeded local JNI references
3902    env->DeleteLocalRef(libString);
3903    env->DeleteLocalRef(classString);
3904
3905    if (pluginClass != 0) {
3906        return static_cast<jclass>(pluginClass);
3907    } else {
3908        return 0;
3909    }
3910}
3911
3912void WebViewCore::showFullScreenPlugin(jobject childView, int32_t orientation, NPP npp)
3913{
3914    JNIEnv* env = JSC::Bindings::getJNIEnv();
3915    AutoJObject javaObject = m_javaGlue->object(env);
3916    if (!javaObject.get())
3917        return;
3918
3919    env->CallVoidMethod(javaObject.get(),
3920                        m_javaGlue->m_showFullScreenPlugin,
3921                        childView, orientation, reinterpret_cast<int>(npp));
3922    checkException(env);
3923}
3924
3925void WebViewCore::hideFullScreenPlugin()
3926{
3927    JNIEnv* env = JSC::Bindings::getJNIEnv();
3928    AutoJObject javaObject = m_javaGlue->object(env);
3929    if (!javaObject.get())
3930        return;
3931    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_hideFullScreenPlugin);
3932    checkException(env);
3933}
3934
3935jobject WebViewCore::createSurface(jobject view)
3936{
3937    JNIEnv* env = JSC::Bindings::getJNIEnv();
3938    AutoJObject javaObject = m_javaGlue->object(env);
3939    if (!javaObject.get())
3940        return 0;
3941    jobject result = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_createSurface, view);
3942    checkException(env);
3943    return result;
3944}
3945
3946jobject WebViewCore::addSurface(jobject view, int x, int y, int width, int height)
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(),
3953                                           m_javaGlue->m_addSurface,
3954                                           view, x, y, width, height);
3955    checkException(env);
3956    return result;
3957}
3958
3959void WebViewCore::updateSurface(jobject childView, int x, int y, int width, int height)
3960{
3961    JNIEnv* env = JSC::Bindings::getJNIEnv();
3962    AutoJObject javaObject = m_javaGlue->object(env);
3963    if (!javaObject.get())
3964        return;
3965    env->CallVoidMethod(javaObject.get(),
3966                        m_javaGlue->m_updateSurface, childView,
3967                        x, y, width, height);
3968    checkException(env);
3969}
3970
3971void WebViewCore::destroySurface(jobject childView)
3972{
3973    JNIEnv* env = JSC::Bindings::getJNIEnv();
3974    AutoJObject javaObject = m_javaGlue->object(env);
3975    if (!javaObject.get())
3976        return;
3977    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_destroySurface, childView);
3978    checkException(env);
3979}
3980
3981jobject WebViewCore::getContext()
3982{
3983    JNIEnv* env = JSC::Bindings::getJNIEnv();
3984    AutoJObject javaObject = m_javaGlue->object(env);
3985    if (!javaObject.get())
3986        return 0;
3987
3988    jobject result = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_getContext);
3989    checkException(env);
3990    return result;
3991}
3992
3993void WebViewCore::keepScreenOn(bool screenOn) {
3994    if ((screenOn && m_screenOnCounter == 0) || (!screenOn && m_screenOnCounter == 1)) {
3995        JNIEnv* env = JSC::Bindings::getJNIEnv();
3996        AutoJObject javaObject = m_javaGlue->object(env);
3997        if (!javaObject.get())
3998            return;
3999        env->CallVoidMethod(javaObject.get(), m_javaGlue->m_keepScreenOn, screenOn);
4000        checkException(env);
4001    }
4002
4003    // update the counter
4004    if (screenOn)
4005        m_screenOnCounter++;
4006    else if (m_screenOnCounter > 0)
4007        m_screenOnCounter--;
4008}
4009
4010bool WebViewCore::validNodeAndBounds(Frame* frame, Node* node,
4011    const IntRect& originalAbsoluteBounds)
4012{
4013    bool valid = validNode(m_mainFrame, frame, node);
4014    if (!valid)
4015        return false;
4016    RenderObject* renderer = node->renderer();
4017    if (!renderer)
4018        return false;
4019    IntRect absBounds = node->hasTagName(HTMLNames::areaTag)
4020        ? getAreaRect(static_cast<HTMLAreaElement*>(node))
4021        : renderer->absoluteBoundingBoxRect();
4022    return absBounds == originalAbsoluteBounds;
4023}
4024
4025void WebViewCore::showRect(int left, int top, int width, int height,
4026        int contentWidth, int contentHeight, float xPercentInDoc,
4027        float xPercentInView, float yPercentInDoc, float yPercentInView)
4028{
4029    JNIEnv* env = JSC::Bindings::getJNIEnv();
4030    AutoJObject javaObject = m_javaGlue->object(env);
4031    if (!javaObject.get())
4032        return;
4033    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_showRect,
4034            left, top, width, height, contentWidth, contentHeight,
4035            xPercentInDoc, xPercentInView, yPercentInDoc, yPercentInView);
4036    checkException(env);
4037}
4038
4039void WebViewCore::centerFitRect(int x, int y, int width, int height)
4040{
4041    JNIEnv* env = JSC::Bindings::getJNIEnv();
4042    AutoJObject javaObject = m_javaGlue->object(env);
4043    if (!javaObject.get())
4044        return;
4045    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_centerFitRect, x, y, width, height);
4046    checkException(env);
4047}
4048
4049void WebViewCore::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode verticalMode)
4050{
4051    JNIEnv* env = JSC::Bindings::getJNIEnv();
4052    AutoJObject javaObject = m_javaGlue->object(env);
4053    if (!javaObject.get())
4054        return;
4055    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_setScrollbarModes, horizontalMode, verticalMode);
4056    checkException(env);
4057}
4058
4059void WebViewCore::notifyWebAppCanBeInstalled()
4060{
4061    JNIEnv* env = JSC::Bindings::getJNIEnv();
4062    AutoJObject javaObject = m_javaGlue->object(env);
4063    if (!javaObject.get())
4064        return;
4065    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_setInstallableWebApp);
4066    checkException(env);
4067}
4068
4069#if ENABLE(VIDEO)
4070void WebViewCore::enterFullscreenForVideoLayer(int layerId, const WTF::String& url)
4071{
4072    JNIEnv* env = JSC::Bindings::getJNIEnv();
4073    AutoJObject javaObject = m_javaGlue->object(env);
4074    if (!javaObject.get())
4075        return;
4076    jstring jUrlStr = wtfStringToJstring(env, url);
4077    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_enterFullscreenForVideoLayer, layerId, jUrlStr);
4078    m_fullscreenVideoMode = true;
4079    checkException(env);
4080}
4081
4082void WebViewCore::exitFullscreenVideo()
4083{
4084    JNIEnv* env = JSC::Bindings::getJNIEnv();
4085    AutoJObject javaObject = m_javaGlue->object(env);
4086    if (!javaObject.get())
4087        return;
4088    if (m_fullscreenVideoMode) {
4089        env->CallVoidMethod(javaObject.get(), m_javaGlue->m_exitFullscreenVideo);
4090        m_fullscreenVideoMode = false;
4091    }
4092    checkException(env);
4093}
4094#endif
4095
4096void WebViewCore::setWebTextViewAutoFillable(int queryId, const string16& previewSummary)
4097{
4098#if ENABLE(WEB_AUTOFILL)
4099    JNIEnv* env = JSC::Bindings::getJNIEnv();
4100    AutoJObject javaObject = m_javaGlue->object(env);
4101    if (!javaObject.get())
4102        return;
4103    jstring preview = env->NewString(previewSummary.data(), previewSummary.length());
4104    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_setWebTextViewAutoFillable, queryId, preview);
4105    env->DeleteLocalRef(preview);
4106#endif
4107}
4108
4109bool WebViewCore::drawIsPaused() const
4110{
4111    // returning true says scrollview should be offscreen, which pauses
4112    // gifs. because this is not again queried when we stop scrolling, we don't
4113    // use the stopping currently.
4114    return false;
4115}
4116
4117void WebViewCore::setWebRequestContextUserAgent()
4118{
4119    // We cannot create a WebRequestContext, because we might not know it this is a private tab or not yet
4120    if (m_webRequestContext)
4121        m_webRequestContext->setUserAgent(WebFrame::getWebFrame(m_mainFrame)->userAgentForURL(0)); // URL not used
4122}
4123
4124void WebViewCore::setWebRequestContextCacheMode(int cacheMode)
4125{
4126    m_cacheMode = cacheMode;
4127    // We cannot create a WebRequestContext, because we might not know it this is a private tab or not yet
4128    if (!m_webRequestContext)
4129        return;
4130
4131    m_webRequestContext->setCacheMode(cacheMode);
4132}
4133
4134WebRequestContext* WebViewCore::webRequestContext()
4135{
4136    if (!m_webRequestContext) {
4137        Settings* settings = mainFrame()->settings();
4138        m_webRequestContext = new WebRequestContext(settings && settings->privateBrowsingEnabled());
4139        setWebRequestContextUserAgent();
4140        setWebRequestContextCacheMode(m_cacheMode);
4141    }
4142    return m_webRequestContext.get();
4143}
4144
4145void WebViewCore::scrollRenderLayer(int layer, const SkRect& rect)
4146{
4147#if USE(ACCELERATED_COMPOSITING)
4148    GraphicsLayerAndroid* root = graphicsRootLayer();
4149    if (!root)
4150        return;
4151
4152    LayerAndroid* layerAndroid = root->platformLayer();
4153    if (!layerAndroid)
4154        return;
4155
4156    LayerAndroid* target = layerAndroid->findById(layer);
4157    if (!target)
4158        return;
4159
4160    RenderLayer* owner = target->owningLayer();
4161    if (!owner)
4162        return;
4163
4164    owner->scrollToOffset(rect.fLeft, rect.fTop);
4165#endif
4166}
4167
4168Vector<VisibleSelection> WebViewCore::getTextRanges(
4169        int startX, int startY, int endX, int endY)
4170{
4171    // These are the positions of the selection handles,
4172    // which reside below the line that they are selecting.
4173    // Use the vertical position higher, which will include
4174    // the selected text.
4175    startY--;
4176    endY--;
4177    VisiblePosition startSelect = visiblePositionForContentPoint(startX, startY);
4178    VisiblePosition endSelect =  visiblePositionForContentPoint(endX, endY);
4179    Position start = startSelect.deepEquivalent();
4180    Position end = endSelect.deepEquivalent();
4181    Vector<VisibleSelection> ranges;
4182    if (!start.isNull() && !end.isNull()) {
4183        if (comparePositions(start, end) > 0) {
4184            swap(start, end); // RTL start/end positions may be swapped
4185        }
4186        Position nextRangeStart = start;
4187        Position previousRangeEnd;
4188        int i = 0;
4189        do {
4190            VisibleSelection selection(nextRangeStart, end);
4191            ranges.append(selection);
4192            previousRangeEnd = selection.end();
4193            nextRangeStart = nextCandidate(previousRangeEnd);
4194        } while (comparePositions(previousRangeEnd, end) < 0);
4195    }
4196    return ranges;
4197}
4198
4199void WebViewCore::deleteText(int startX, int startY, int endX, int endY)
4200{
4201    Vector<VisibleSelection> ranges =
4202            getTextRanges(startX, startY, endX, endY);
4203
4204    EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
4205            m_mainFrame->editor()->client());
4206    client->setUiGeneratedSelectionChange(true);
4207
4208    SelectionController* selector = m_mainFrame->selection();
4209    for (size_t i = 0; i < ranges.size(); i++) {
4210        const VisibleSelection& selection = ranges[i];
4211        if (selection.isContentEditable()) {
4212            selector->setSelection(selection, CharacterGranularity);
4213            Document* document = selection.start().anchorNode()->document();
4214            WebCore::TypingCommand::deleteSelection(document, 0);
4215        }
4216    }
4217    client->setUiGeneratedSelectionChange(false);
4218}
4219
4220void WebViewCore::insertText(const WTF::String &text)
4221{
4222    WebCore::Node* focus = currentFocus();
4223    if (!focus || !isTextInput(focus))
4224        return;
4225
4226    Document* document = focus->document();
4227    Frame* frame = document->frame();
4228
4229    EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
4230            m_mainFrame->editor()->client());
4231    if (!client)
4232        return;
4233    client->setUiGeneratedSelectionChange(true);
4234    WebCore::TypingCommand::insertText(document, text,
4235            TypingCommand::PreventSpellChecking);
4236    client->setUiGeneratedSelectionChange(false);
4237}
4238
4239void WebViewCore::resetFindOnPage()
4240{
4241    m_searchText.truncate(0);
4242    m_matchCount = 0;
4243    m_activeMatchIndex = 0;
4244    m_activeMatch = 0;
4245}
4246
4247int WebViewCore::findTextOnPage(const WTF::String &text)
4248{
4249    resetFindOnPage(); // reset even if parameters are bad
4250
4251    WebCore::Frame* frame = m_mainFrame;
4252    if (!frame)
4253        return 0;
4254
4255    m_searchText = text;
4256    FindOptions findOptions = WebCore::CaseInsensitive;
4257
4258    do {
4259        frame->document()->markers()->removeMarkers(DocumentMarker::TextMatch);
4260        m_matchCount += frame->editor()->countMatchesForText(text, findOptions,
4261            0, true);
4262        updateMatchCount();
4263        frame->editor()->setMarkedTextMatchesAreHighlighted(true);
4264        frame = frame->tree()->traverseNextWithWrap(false);
4265    } while (frame);
4266
4267    m_activeMatchIndex = m_matchCount - 1; // prime first findNext
4268    findNextOnPage(true);
4269    return m_matchCount;
4270}
4271
4272void WebViewCore::findNextOnPage(bool forward)
4273{
4274    if (!m_mainFrame)
4275        return;
4276    if (!m_matchCount)
4277        return;
4278
4279    EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
4280        m_mainFrame->editor()->client());
4281    client->setUiGeneratedSelectionChange(true);
4282
4283    // Clear previous active match.
4284    if (m_activeMatch) {
4285        m_mainFrame->document()->markers()->setMarkersActive(
4286            m_activeMatch.get(), false);
4287    }
4288
4289    FindOptions findOptions = WebCore::CaseInsensitive
4290        | WebCore::StartInSelection | WebCore::WrapAround;
4291    if (!forward)
4292        findOptions |= WebCore::Backwards;
4293
4294    // Start from the previous active match.
4295    if (m_activeMatch) {
4296        m_mainFrame->selection()->setSelection(m_activeMatch.get());
4297    }
4298
4299    bool found = m_mainFrame->editor()->findString(m_searchText, findOptions);
4300    if (found) {
4301        VisibleSelection selection(m_mainFrame->selection()->selection());
4302        if (selection.isNone() || selection.start() == selection.end()) {
4303            // Temporary workaround for findString() refusing to select text
4304            // marked "-webkit-user-select: none".
4305            m_activeMatchIndex = 0;
4306            m_activeMatch = 0;
4307        } else {
4308            // Mark current match "active".
4309            if (forward) {
4310                ++m_activeMatchIndex;
4311                if (m_activeMatchIndex == m_matchCount)
4312                    m_activeMatchIndex = 0;
4313            } else {
4314                if (m_activeMatchIndex == 0)
4315                    m_activeMatchIndex = m_matchCount;
4316                --m_activeMatchIndex;
4317            }
4318            m_activeMatch = selection.firstRange();
4319            m_mainFrame->document()->markers()->setMarkersActive(
4320                m_activeMatch.get(), true);
4321            m_mainFrame->selection()->revealSelection(
4322                ScrollAlignment::alignCenterIfNeeded, true);
4323        }
4324        updateMatchCount();
4325    }
4326
4327    // Clear selection so it doesn't display.
4328    m_mainFrame->selection()->clear();
4329    client->setUiGeneratedSelectionChange(false);
4330}
4331
4332void WebViewCore::updateMatchCount() const
4333{
4334    JNIEnv* env = JSC::Bindings::getJNIEnv();
4335    AutoJObject javaObject = m_javaGlue->object(env);
4336    if (!javaObject.get())
4337        return;
4338    jstring javaText = wtfStringToJstring(env, m_searchText, true);
4339    env->CallVoidMethod(javaObject.get(), m_javaGlue->m_updateMatchCount,
4340        m_activeMatchIndex, m_matchCount, javaText);
4341    checkException(env);
4342}
4343
4344String WebViewCore::getText(int startX, int startY, int endX, int endY)
4345{
4346    String text;
4347
4348    Vector<VisibleSelection> ranges =
4349            getTextRanges(startX, startY, endX, endY);
4350
4351    for (size_t i = 0; i < ranges.size(); i++) {
4352        const VisibleSelection& selection = ranges[i];
4353        PassRefPtr<Range> range = selection.firstRange();
4354        String textInRange = range->text();
4355        if (textInRange.length() > 0) {
4356            if (text.length() > 0)
4357                text.append('\n');
4358            text.append(textInRange);
4359        }
4360    }
4361
4362    return text;
4363}
4364
4365//----------------------------------------------------------------------
4366// Native JNI methods
4367//----------------------------------------------------------------------
4368static void RevealSelection(JNIEnv* env, jobject obj, jint nativeClass)
4369{
4370    reinterpret_cast<WebViewCore*>(nativeClass)->revealSelection();
4371}
4372
4373static jstring RequestLabel(JNIEnv* env, jobject obj, jint nativeClass,
4374        int framePointer, int nodePointer)
4375{
4376    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4377    return wtfStringToJstring(env, viewImpl->requestLabel(
4378            (WebCore::Frame*) framePointer, (WebCore::Node*) nodePointer));
4379}
4380
4381static void ClearContent(JNIEnv* env, jobject obj, jint nativeClass)
4382{
4383    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4384    viewImpl->clearContent();
4385}
4386
4387static void UpdateFrameCacheIfLoading(JNIEnv* env, jobject obj, jint nativeClass)
4388{
4389}
4390
4391static void SetSize(JNIEnv* env, jobject obj, jint nativeClass, jint width,
4392        jint height, jint textWrapWidth, jfloat scale, jint screenWidth,
4393        jint screenHeight, jint anchorX, jint anchorY, jboolean ignoreHeight)
4394{
4395    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4396    ALOGV("webviewcore::nativeSetSize(%u %u)\n viewImpl: %p", (unsigned)width, (unsigned)height, viewImpl);
4397    ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSetSize");
4398    viewImpl->setSizeScreenWidthAndScale(width, height, textWrapWidth, scale,
4399            screenWidth, screenHeight, anchorX, anchorY, ignoreHeight);
4400}
4401
4402static void SetScrollOffset(JNIEnv* env, jobject obj, jint nativeClass,
4403        jint gen, jboolean sendScrollEvent, jint x, jint y)
4404{
4405    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4406    ALOG_ASSERT(viewImpl, "need viewImpl");
4407
4408    viewImpl->setScrollOffset(gen, sendScrollEvent, x, y);
4409}
4410
4411static void SetGlobalBounds(JNIEnv* env, jobject obj, jint nativeClass,
4412        jint x, jint y, jint h, jint v)
4413{
4414    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4415    ALOG_ASSERT(viewImpl, "need viewImpl");
4416
4417    viewImpl->setGlobalBounds(x, y, h, v);
4418}
4419
4420static jboolean Key(JNIEnv* env, jobject obj, jint nativeClass, jint keyCode,
4421        jint unichar, jint repeatCount, jboolean isShift, jboolean isAlt,
4422        jboolean isSym, jboolean isDown)
4423{
4424    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4425    return viewImpl->key(PlatformKeyboardEvent(keyCode,
4426        unichar, repeatCount, isDown, isShift, isAlt, isSym));
4427}
4428
4429static void Click(JNIEnv* env, jobject obj, jint nativeClass, int framePtr,
4430        int nodePtr, jboolean fake)
4431{
4432    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4433    ALOG_ASSERT(viewImpl, "viewImpl not set in Click");
4434
4435    viewImpl->click(reinterpret_cast<WebCore::Frame*>(framePtr),
4436        reinterpret_cast<WebCore::Node*>(nodePtr), fake);
4437}
4438
4439static void ContentInvalidateAll(JNIEnv* env, jobject obj, jint nativeClass)
4440{
4441    reinterpret_cast<WebViewCore*>(nativeClass)->contentInvalidateAll();
4442}
4443
4444static void DeleteSelection(JNIEnv* env, jobject obj, jint nativeClass,
4445        jint start, jint end, jint textGeneration)
4446{
4447    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4448    viewImpl->deleteSelection(start, end, textGeneration);
4449}
4450
4451static void SetSelection(JNIEnv* env, jobject obj, jint nativeClass,
4452        jint start, jint end)
4453{
4454    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4455    viewImpl->setSelection(start, end);
4456}
4457
4458static jstring ModifySelection(JNIEnv* env, jobject obj, jint nativeClass,
4459        jint direction, jint granularity)
4460{
4461    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4462    String selectionString = viewImpl->modifySelection(direction, granularity);
4463    return wtfStringToJstring(env, selectionString);
4464}
4465
4466static void ReplaceTextfieldText(JNIEnv* env, jobject obj, jint nativeClass,
4467    jint oldStart, jint oldEnd, jstring replace, jint start, jint end,
4468    jint textGeneration)
4469{
4470    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4471    WTF::String webcoreString = jstringToWtfString(env, replace);
4472    viewImpl->replaceTextfieldText(oldStart,
4473            oldEnd, webcoreString, start, end, textGeneration);
4474}
4475
4476static void PassToJs(JNIEnv* env, jobject obj, jint nativeClass,
4477    jint generation, jstring currentText, jint keyCode,
4478    jint keyValue, jboolean down, jboolean cap, jboolean fn, jboolean sym)
4479{
4480    WTF::String current = jstringToWtfString(env, currentText);
4481    reinterpret_cast<WebViewCore*>(nativeClass)->passToJs(generation, current,
4482        PlatformKeyboardEvent(keyCode, keyValue, 0, down, cap, fn, sym));
4483}
4484
4485static void ScrollFocusedTextInput(JNIEnv* env, jobject obj, jint nativeClass,
4486        jfloat xPercent, jint y)
4487{
4488    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4489    viewImpl->scrollFocusedTextInput(xPercent, y);
4490}
4491
4492static void SetFocusControllerActive(JNIEnv* env, jobject obj, jint nativeClass,
4493        jboolean active)
4494{
4495    ALOGV("webviewcore::nativeSetFocusControllerActive()\n");
4496    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4497    ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSetFocusControllerActive");
4498    viewImpl->setFocusControllerActive(active);
4499}
4500
4501static void SaveDocumentState(JNIEnv* env, jobject obj, jint nativeClass,
4502        jint frame)
4503{
4504    ALOGV("webviewcore::nativeSaveDocumentState()\n");
4505    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4506    ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSaveDocumentState");
4507    viewImpl->saveDocumentState((WebCore::Frame*) frame);
4508}
4509
4510void WebViewCore::addVisitedLink(const UChar* string, int length)
4511{
4512    if (m_groupForVisitedLinks)
4513        m_groupForVisitedLinks->addVisitedLink(string, length);
4514}
4515
4516static bool UpdateLayers(JNIEnv* env, jobject obj, jint nativeClass,
4517        jint jbaseLayer)
4518{
4519    WebViewCore* viewImpl = (WebViewCore*) nativeClass;
4520    BaseLayerAndroid* baseLayer = (BaseLayerAndroid*)  jbaseLayer;
4521    if (baseLayer) {
4522        LayerAndroid* root = static_cast<LayerAndroid*>(baseLayer->getChild(0));
4523        if (root)
4524            return viewImpl->updateLayers(root);
4525    }
4526    return true;
4527}
4528
4529static void NotifyAnimationStarted(JNIEnv* env, jobject obj, jint nativeClass)
4530{
4531    WebViewCore* viewImpl = (WebViewCore*) nativeClass;
4532    viewImpl->notifyAnimationStarted();
4533}
4534
4535static jint RecordContent(JNIEnv* env, jobject obj, jint nativeClass,
4536        jobject region, jobject pt)
4537{
4538    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4539    SkRegion* nativeRegion = GraphicsJNI::getNativeRegion(env, region);
4540    SkIPoint nativePt;
4541    BaseLayerAndroid* result = viewImpl->recordContent(nativeRegion, &nativePt);
4542    GraphicsJNI::ipoint_to_jpoint(nativePt, env, pt);
4543    return reinterpret_cast<jint>(result);
4544}
4545
4546static void SplitContent(JNIEnv* env, jobject obj, jint nativeClass,
4547        jint content)
4548{
4549    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4550    viewImpl->splitContent(reinterpret_cast<PictureSet*>(content));
4551}
4552
4553static void SendListBoxChoice(JNIEnv* env, jobject obj, jint nativeClass,
4554        jint choice)
4555{
4556    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4557    ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoice");
4558    viewImpl->popupReply(choice);
4559}
4560
4561// Set aside a predetermined amount of space in which to place the listbox
4562// choices, to avoid unnecessary allocations.
4563// The size here is arbitrary.  We want the size to be at least as great as the
4564// number of items in the average multiple-select listbox.
4565#define PREPARED_LISTBOX_STORAGE 10
4566
4567static void SendListBoxChoices(JNIEnv* env, jobject obj, jint nativeClass,
4568        jbooleanArray jArray, jint size)
4569{
4570    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4571    ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoices");
4572    jboolean* ptrArray = env->GetBooleanArrayElements(jArray, 0);
4573    SkAutoSTMalloc<PREPARED_LISTBOX_STORAGE, int> storage(size);
4574    int* array = storage.get();
4575    int count = 0;
4576    for (int i = 0; i < size; i++) {
4577        if (ptrArray[i]) {
4578            array[count++] = i;
4579        }
4580    }
4581    env->ReleaseBooleanArrayElements(jArray, ptrArray, JNI_ABORT);
4582    viewImpl->popupReply(array, count);
4583}
4584
4585// TODO: Move this to WebView.cpp since it is only needed there
4586static jstring FindAddress(JNIEnv* env, jobject obj, jstring addr,
4587        jboolean caseInsensitive)
4588{
4589    if (!addr)
4590        return 0;
4591    int length = env->GetStringLength(addr);
4592    if (!length)
4593        return 0;
4594    const jchar* addrChars = env->GetStringChars(addr, 0);
4595    size_t start, end;
4596    AddressDetector detector;
4597    bool success = detector.FindContent(addrChars, addrChars + length, &start, &end);
4598    jstring ret = 0;
4599    if (success)
4600        ret = env->NewString(addrChars + start, end - start);
4601    env->ReleaseStringChars(addr, addrChars);
4602    return ret;
4603}
4604
4605static jboolean HandleTouchEvent(JNIEnv* env, jobject obj, jint nativeClass,
4606        jint action, jintArray idArray, jintArray xArray, jintArray yArray,
4607        jint count, jint actionIndex, jint metaState)
4608{
4609    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4610    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4611    jint* ptrIdArray = env->GetIntArrayElements(idArray, 0);
4612    jint* ptrXArray = env->GetIntArrayElements(xArray, 0);
4613    jint* ptrYArray = env->GetIntArrayElements(yArray, 0);
4614    Vector<int> ids(count);
4615    Vector<IntPoint> points(count);
4616    for (int c = 0; c < count; c++) {
4617        ids[c] = ptrIdArray[c];
4618        points[c].setX(ptrXArray[c]);
4619        points[c].setY(ptrYArray[c]);
4620    }
4621    env->ReleaseIntArrayElements(idArray, ptrIdArray, JNI_ABORT);
4622    env->ReleaseIntArrayElements(xArray, ptrXArray, JNI_ABORT);
4623    env->ReleaseIntArrayElements(yArray, ptrYArray, JNI_ABORT);
4624
4625    return viewImpl->handleTouchEvent(action, ids, points, actionIndex, metaState);
4626}
4627
4628static void TouchUp(JNIEnv* env, jobject obj, jint nativeClass,
4629        jint touchGeneration, jint frame, jint node, jint x, jint y)
4630{
4631    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4632    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4633    viewImpl->touchUp(touchGeneration,
4634        (WebCore::Frame*) frame, (WebCore::Node*) node, x, y);
4635}
4636
4637static jstring RetrieveHref(JNIEnv* env, jobject obj, jint nativeClass,
4638        jint x, jint y)
4639{
4640    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4641    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4642    WTF::String result = viewImpl->retrieveHref(x, y);
4643    if (!result.isEmpty())
4644        return wtfStringToJstring(env, result);
4645    return 0;
4646}
4647
4648static jstring RetrieveAnchorText(JNIEnv* env, jobject obj, jint nativeClass,
4649        jint x, jint y)
4650{
4651    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4652    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4653    WTF::String result = viewImpl->retrieveAnchorText(x, y);
4654    if (!result.isEmpty())
4655        return wtfStringToJstring(env, result);
4656    return 0;
4657}
4658
4659static jstring RetrieveImageSource(JNIEnv* env, jobject obj, jint nativeClass,
4660        jint x, jint y)
4661{
4662    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4663    WTF::String result = viewImpl->retrieveImageSource(x, y);
4664    return !result.isEmpty() ? wtfStringToJstring(env, result) : 0;
4665}
4666
4667static void MoveFocus(JNIEnv* env, jobject obj, jint nativeClass, jint framePtr,
4668        jint nodePtr)
4669{
4670    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4671    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4672    viewImpl->moveFocus((WebCore::Frame*) framePtr, (WebCore::Node*) nodePtr);
4673}
4674
4675static void MoveMouse(JNIEnv* env, jobject obj, jint nativeClass, jint frame,
4676        jint x, jint y)
4677{
4678    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4679    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4680    viewImpl->moveMouse((WebCore::Frame*) frame, x, y);
4681}
4682
4683static void MoveMouseIfLatest(JNIEnv* env, jobject obj, jint nativeClass,
4684        jint moveGeneration, jint frame, jint x, jint y)
4685{
4686    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4687    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4688    viewImpl->moveMouseIfLatest(moveGeneration,
4689        (WebCore::Frame*) frame, x, y);
4690}
4691
4692static void UpdateFrameCache(JNIEnv* env, jobject obj, jint nativeClass)
4693{
4694}
4695
4696static jint GetContentMinPrefWidth(JNIEnv* env, jobject obj, jint nativeClass)
4697{
4698    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4699    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4700
4701    WebCore::Frame* frame = viewImpl->mainFrame();
4702    if (frame) {
4703        WebCore::Document* document = frame->document();
4704        if (document) {
4705            WebCore::RenderObject* renderer = document->renderer();
4706            if (renderer && renderer->isRenderView()) {
4707                return renderer->minPreferredLogicalWidth();
4708            }
4709        }
4710    }
4711    return 0;
4712}
4713
4714static void SetViewportSettingsFromNative(JNIEnv* env, jobject obj,
4715        jint nativeClass)
4716{
4717    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4718    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4719
4720    WebCore::Settings* s = viewImpl->mainFrame()->page()->settings();
4721    if (!s)
4722        return;
4723
4724#ifdef ANDROID_META_SUPPORT
4725    env->SetIntField(obj, gWebViewCoreFields.m_viewportWidth, s->viewportWidth());
4726    env->SetIntField(obj, gWebViewCoreFields.m_viewportHeight, s->viewportHeight());
4727    env->SetIntField(obj, gWebViewCoreFields.m_viewportInitialScale, s->viewportInitialScale());
4728    env->SetIntField(obj, gWebViewCoreFields.m_viewportMinimumScale, s->viewportMinimumScale());
4729    env->SetIntField(obj, gWebViewCoreFields.m_viewportMaximumScale, s->viewportMaximumScale());
4730    env->SetBooleanField(obj, gWebViewCoreFields.m_viewportUserScalable, s->viewportUserScalable());
4731    env->SetIntField(obj, gWebViewCoreFields.m_viewportDensityDpi, s->viewportTargetDensityDpi());
4732#endif
4733}
4734
4735static void SetBackgroundColor(JNIEnv* env, jobject obj, jint nativeClass,
4736        jint color)
4737{
4738    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4739    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4740
4741    viewImpl->setBackgroundColor((SkColor) color);
4742}
4743
4744static void DumpDomTree(JNIEnv* env, jobject obj, jint nativeClass,
4745        jboolean useFile)
4746{
4747    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4748    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4749
4750    viewImpl->dumpDomTree(useFile);
4751}
4752
4753static void DumpRenderTree(JNIEnv* env, jobject obj, jint nativeClass,
4754        jboolean useFile)
4755{
4756    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4757    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4758
4759    viewImpl->dumpRenderTree(useFile);
4760}
4761
4762static void DumpNavTree(JNIEnv* env, jobject obj, jint nativeClass)
4763{
4764}
4765
4766static void SetJsFlags(JNIEnv* env, jobject obj, jint nativeClass, jstring flags)
4767{
4768    WTF::String flagsString = jstringToWtfString(env, flags);
4769    WTF::CString utf8String = flagsString.utf8();
4770    WebCore::ScriptController::setFlags(utf8String.data(), utf8String.length());
4771}
4772
4773
4774// Called from the Java side to set a new quota for the origin or new appcache
4775// max size in response to a notification that the original quota was exceeded or
4776// that the appcache has reached its maximum size.
4777static void SetNewStorageLimit(JNIEnv* env, jobject obj, jint nativeClass,
4778        jlong quota)
4779{
4780#if ENABLE(DATABASE) || ENABLE(OFFLINE_WEB_APPLICATIONS)
4781    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4782    Frame* frame = viewImpl->mainFrame();
4783
4784    // The main thread is blocked awaiting this response, so now we can wake it
4785    // up.
4786    ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client());
4787    chromeC->wakeUpMainThreadWithNewQuota(quota);
4788#endif
4789}
4790
4791// Called from Java to provide a Geolocation permission state for the specified origin.
4792static void GeolocationPermissionsProvide(JNIEnv* env, jobject obj,
4793        jint nativeClass, jstring origin, jboolean allow, jboolean remember)
4794{
4795    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4796    Frame* frame = viewImpl->mainFrame();
4797
4798    ChromeClientAndroid* chromeClient = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client());
4799    chromeClient->provideGeolocationPermissions(jstringToWtfString(env, origin), allow, remember);
4800}
4801
4802static void RegisterURLSchemeAsLocal(JNIEnv* env, jobject obj, jint nativeClass,
4803        jstring scheme)
4804{
4805    WebCore::SchemeRegistry::registerURLSchemeAsLocal(jstringToWtfString(env, scheme));
4806}
4807
4808static bool FocusBoundsChanged(JNIEnv* env, jobject obj, jint nativeClass)
4809{
4810    return reinterpret_cast<WebViewCore*>(nativeClass)->focusBoundsChanged();
4811}
4812
4813static void SetIsPaused(JNIEnv* env, jobject obj, jint nativeClass,
4814        jboolean isPaused)
4815{
4816    // tell the webcore thread to stop thinking while we do other work
4817    // (selection and scrolling). This has nothing to do with the lifecycle
4818    // pause and resume.
4819    reinterpret_cast<WebViewCore*>(nativeClass)->setIsPaused(isPaused);
4820}
4821
4822static void Pause(JNIEnv* env, jobject obj, jint nativeClass)
4823{
4824    // This is called for the foreground tab when the browser is put to the
4825    // background (and also for any tab when it is put to the background of the
4826    // browser). The browser can only be killed by the system when it is in the
4827    // background, so saving the Geolocation permission state now ensures that
4828    // is maintained when the browser is killed.
4829    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4830    ChromeClient* chromeClient = viewImpl->mainFrame()->page()->chrome()->client();
4831    ChromeClientAndroid* chromeClientAndroid = static_cast<ChromeClientAndroid*>(chromeClient);
4832    chromeClientAndroid->storeGeolocationPermissions();
4833
4834    Frame* mainFrame = viewImpl->mainFrame();
4835    for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) {
4836        Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation();
4837        if (geolocation)
4838            geolocation->suspend();
4839    }
4840
4841    viewImpl->deviceMotionAndOrientationManager()->maybeSuspendClients();
4842
4843    ANPEvent event;
4844    SkANP::InitEvent(&event, kLifecycle_ANPEventType);
4845    event.data.lifecycle.action = kPause_ANPLifecycleAction;
4846    viewImpl->sendPluginEvent(event);
4847
4848    viewImpl->setIsPaused(true);
4849}
4850
4851static void Resume(JNIEnv* env, jobject obj, jint nativeClass)
4852{
4853    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4854    Frame* mainFrame = viewImpl->mainFrame();
4855    for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) {
4856        Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation();
4857        if (geolocation)
4858            geolocation->resume();
4859    }
4860
4861    viewImpl->deviceMotionAndOrientationManager()->maybeResumeClients();
4862
4863    ANPEvent event;
4864    SkANP::InitEvent(&event, kLifecycle_ANPEventType);
4865    event.data.lifecycle.action = kResume_ANPLifecycleAction;
4866    viewImpl->sendPluginEvent(event);
4867
4868    viewImpl->setIsPaused(false);
4869}
4870
4871static void FreeMemory(JNIEnv* env, jobject obj, jint nativeClass)
4872{
4873    ANPEvent event;
4874    SkANP::InitEvent(&event, kLifecycle_ANPEventType);
4875    event.data.lifecycle.action = kFreeMemory_ANPLifecycleAction;
4876    reinterpret_cast<WebViewCore*>(nativeClass)->sendPluginEvent(event);
4877}
4878
4879static void ProvideVisitedHistory(JNIEnv* env, jobject obj, jint nativeClass,
4880        jobject hist)
4881{
4882    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4883    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4884
4885    jobjectArray array = static_cast<jobjectArray>(hist);
4886
4887    jsize len = env->GetArrayLength(array);
4888    for (jsize i = 0; i < len; i++) {
4889        jstring item = static_cast<jstring>(env->GetObjectArrayElement(array, i));
4890        const UChar* str = static_cast<const UChar*>(env->GetStringChars(item, 0));
4891        jsize len = env->GetStringLength(item);
4892        viewImpl->addVisitedLink(str, len);
4893        env->ReleaseStringChars(item, str);
4894        env->DeleteLocalRef(item);
4895    }
4896}
4897
4898static void PluginSurfaceReady(JNIEnv* env, jobject obj, jint nativeClass)
4899{
4900    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4901    if (viewImpl)
4902        viewImpl->sendPluginSurfaceReady();
4903}
4904
4905// Notification from the UI thread that the plugin's full-screen surface has been discarded
4906static void FullScreenPluginHidden(JNIEnv* env, jobject obj, jint nativeClass,
4907        jint npp)
4908{
4909    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4910    PluginWidgetAndroid* plugin = viewImpl->getPluginWidget((NPP)npp);
4911    if (plugin)
4912        plugin->exitFullScreen(false);
4913}
4914
4915static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj)
4916{
4917    int L, T, R, B;
4918    GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B);
4919    return WebCore::IntRect(L, T, R - L, B - T);
4920}
4921
4922static bool ValidNodeAndBounds(JNIEnv* env, jobject obj, jint nativeClass,
4923        int frame, int node, jobject rect)
4924{
4925    IntRect nativeRect = jrect_to_webrect(env, rect);
4926    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4927    return viewImpl->validNodeAndBounds(
4928            reinterpret_cast<Frame*>(frame),
4929            reinterpret_cast<Node*>(node), nativeRect);
4930}
4931
4932static jobject HitTest(JNIEnv* env, jobject obj, jint nativeClass, jint x,
4933                       jint y, jint slop, jboolean doMoveMouse)
4934{
4935    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4936    if (!viewImpl)
4937        return 0;
4938    Node* node = 0;
4939    AndroidHitTestResult result = viewImpl->hitTestAtPoint(x, y, slop, doMoveMouse);
4940    return result.createJavaObject(env);
4941}
4942
4943static void AutoFillForm(JNIEnv* env, jobject obj, jint nativeClass,
4944        jint queryId)
4945{
4946#if ENABLE(WEB_AUTOFILL)
4947    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4948    if (!viewImpl)
4949        return;
4950
4951    WebCore::Frame* frame = viewImpl->mainFrame();
4952    if (frame) {
4953        EditorClientAndroid* editorC = static_cast<EditorClientAndroid*>(frame->page()->editorClient());
4954        WebAutofill* autoFill = editorC->getAutofill();
4955        autoFill->fillFormFields(queryId);
4956    }
4957#endif
4958}
4959
4960static void CloseIdleConnections(JNIEnv* env, jobject obj, jint nativeClass)
4961{
4962    WebCache::get(true)->closeIdleConnections();
4963    WebCache::get(false)->closeIdleConnections();
4964}
4965
4966static void nativeCertTrustChanged(JNIEnv *env, jobject obj)
4967{
4968#if USE(CHROME_NETWORK_STACK)
4969    WebCache::get(true)->certTrustChanged();
4970    WebCache::get(false)->certTrustChanged();
4971#endif
4972}
4973
4974static void ScrollRenderLayer(JNIEnv* env, jobject obj, jint nativeClass,
4975        jint layer, jobject jRect)
4976{
4977    SkRect rect;
4978    GraphicsJNI::jrect_to_rect(env, jRect, &rect);
4979    reinterpret_cast<WebViewCore*>(nativeClass)->scrollRenderLayer(layer, rect);
4980}
4981
4982static void DeleteText(JNIEnv* env, jobject obj, jint nativeClass,
4983        jint startX, jint startY, jint endX, jint endY)
4984{
4985    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4986    viewImpl->deleteText(startX, startY, endX, endY);
4987}
4988
4989static void InsertText(JNIEnv* env, jobject obj, jint nativeClass,
4990        jstring text)
4991{
4992    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4993    WTF::String wtfText = jstringToWtfString(env, text);
4994    viewImpl->insertText(wtfText);
4995}
4996
4997static jobject GetText(JNIEnv* env, jobject obj, jint nativeClass,
4998        jint startX, jint startY, jint endX, jint endY)
4999{
5000    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
5001    WTF::String text = viewImpl->getText(startX, startY, endX, endY);
5002    return text.isEmpty() ? 0 : wtfStringToJstring(env, text);
5003}
5004
5005static void SelectText(JNIEnv* env, jobject obj, jint nativeClass,
5006        jint startX, jint startY, jint endX, jint endY)
5007{
5008    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
5009    viewImpl->selectText(startX, startY, endX, endY);
5010}
5011
5012static void ClearSelection(JNIEnv* env, jobject obj, jint nativeClass)
5013{
5014    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
5015    viewImpl->focusedFrame()->selection()->clear();
5016}
5017
5018static void SelectWordAt(JNIEnv* env, jobject obj, jint nativeClass, jint x, jint y)
5019{
5020    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
5021    viewImpl->selectWordAt(x, y);
5022}
5023
5024static void SelectAll(JNIEnv* env, jobject obj, jint nativeClass)
5025{
5026    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
5027    viewImpl->focusedFrame()->selection()->selectAll();
5028}
5029
5030static int FindAll(JNIEnv* env, jobject obj, jint nativeClass,
5031        jstring text)
5032{
5033    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
5034    WTF::String wtfText = jstringToWtfString(env, text);
5035    return viewImpl->findTextOnPage(wtfText);
5036}
5037
5038static void FindNext(JNIEnv* env, jobject obj, jint nativeClass,
5039        jboolean forward)
5040{
5041    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
5042    viewImpl->findNextOnPage(forward);
5043}
5044
5045// ----------------------------------------------------------------------------
5046
5047/*
5048 * JNI registration.
5049 */
5050static JNINativeMethod gJavaWebViewCoreMethods[] = {
5051    { "nativeClearContent", "(I)V",
5052            (void*) ClearContent },
5053    { "nativeFocusBoundsChanged", "(I)Z",
5054        (void*) FocusBoundsChanged } ,
5055    { "nativeKey", "(IIIIZZZZ)Z",
5056        (void*) Key },
5057    { "nativeClick", "(IIIZ)V",
5058        (void*) Click },
5059    { "nativeContentInvalidateAll", "(I)V",
5060        (void*) ContentInvalidateAll },
5061    { "nativeSendListBoxChoices", "(I[ZI)V",
5062        (void*) SendListBoxChoices },
5063    { "nativeSendListBoxChoice", "(II)V",
5064        (void*) SendListBoxChoice },
5065    { "nativeSetSize", "(IIIIFIIIIZ)V",
5066        (void*) SetSize },
5067    { "nativeSetScrollOffset", "(IIZII)V",
5068        (void*) SetScrollOffset },
5069    { "nativeSetGlobalBounds", "(IIIII)V",
5070        (void*) SetGlobalBounds },
5071    { "nativeSetSelection", "(III)V",
5072        (void*) SetSelection } ,
5073    { "nativeModifySelection", "(III)Ljava/lang/String;",
5074        (void*) ModifySelection },
5075    { "nativeDeleteSelection", "(IIII)V",
5076        (void*) DeleteSelection } ,
5077    { "nativeReplaceTextfieldText", "(IIILjava/lang/String;III)V",
5078        (void*) ReplaceTextfieldText } ,
5079    { "nativeMoveFocus", "(III)V",
5080        (void*) MoveFocus },
5081    { "nativeMoveMouse", "(IIII)V",
5082        (void*) MoveMouse },
5083    { "nativeMoveMouseIfLatest", "(IIIII)V",
5084        (void*) MoveMouseIfLatest },
5085    { "passToJs", "(IILjava/lang/String;IIZZZZ)V",
5086        (void*) PassToJs },
5087    { "nativeScrollFocusedTextInput", "(IFI)V",
5088        (void*) ScrollFocusedTextInput },
5089    { "nativeSetFocusControllerActive", "(IZ)V",
5090        (void*) SetFocusControllerActive },
5091    { "nativeSaveDocumentState", "(II)V",
5092        (void*) SaveDocumentState },
5093    { "nativeFindAddress", "(Ljava/lang/String;Z)Ljava/lang/String;",
5094        (void*) FindAddress },
5095    { "nativeHandleTouchEvent", "(II[I[I[IIII)Z",
5096            (void*) HandleTouchEvent },
5097    { "nativeTouchUp", "(IIIIII)V",
5098        (void*) TouchUp },
5099    { "nativeRetrieveHref", "(III)Ljava/lang/String;",
5100        (void*) RetrieveHref },
5101    { "nativeRetrieveAnchorText", "(III)Ljava/lang/String;",
5102        (void*) RetrieveAnchorText },
5103    { "nativeRetrieveImageSource", "(III)Ljava/lang/String;",
5104        (void*) RetrieveImageSource },
5105    { "nativeUpdateFrameCache", "(I)V",
5106        (void*) UpdateFrameCache },
5107    { "nativeGetContentMinPrefWidth", "(I)I",
5108        (void*) GetContentMinPrefWidth },
5109    { "nativeUpdateLayers", "(II)Z",
5110        (void*) UpdateLayers },
5111    { "nativeNotifyAnimationStarted", "(I)V",
5112        (void*) NotifyAnimationStarted },
5113    { "nativeRecordContent", "(ILandroid/graphics/Region;Landroid/graphics/Point;)I",
5114        (void*) RecordContent },
5115    { "setViewportSettingsFromNative", "(I)V",
5116        (void*) SetViewportSettingsFromNative },
5117    { "nativeSplitContent", "(II)V",
5118        (void*) SplitContent },
5119    { "nativeSetBackgroundColor", "(II)V",
5120        (void*) SetBackgroundColor },
5121    { "nativeRegisterURLSchemeAsLocal", "(ILjava/lang/String;)V",
5122        (void*) RegisterURLSchemeAsLocal },
5123    { "nativeDumpDomTree", "(IZ)V",
5124        (void*) DumpDomTree },
5125    { "nativeDumpRenderTree", "(IZ)V",
5126        (void*) DumpRenderTree },
5127    { "nativeDumpNavTree", "(I)V",
5128        (void*) DumpNavTree },
5129    { "nativeSetNewStorageLimit", "(IJ)V",
5130        (void*) SetNewStorageLimit },
5131    { "nativeGeolocationPermissionsProvide", "(ILjava/lang/String;ZZ)V",
5132        (void*) GeolocationPermissionsProvide },
5133    { "nativeSetIsPaused", "(IZ)V", (void*) SetIsPaused },
5134    { "nativePause", "(I)V", (void*) Pause },
5135    { "nativeResume", "(I)V", (void*) Resume },
5136    { "nativeFreeMemory", "(I)V", (void*) FreeMemory },
5137    { "nativeSetJsFlags", "(ILjava/lang/String;)V", (void*) SetJsFlags },
5138    { "nativeRequestLabel", "(III)Ljava/lang/String;",
5139        (void*) RequestLabel },
5140    { "nativeRevealSelection", "(I)V", (void*) RevealSelection },
5141    { "nativeUpdateFrameCacheIfLoading", "(I)V",
5142        (void*) UpdateFrameCacheIfLoading },
5143    { "nativeProvideVisitedHistory", "(I[Ljava/lang/String;)V",
5144        (void*) ProvideVisitedHistory },
5145    { "nativeFullScreenPluginHidden", "(II)V",
5146        (void*) FullScreenPluginHidden },
5147    { "nativePluginSurfaceReady", "(I)V",
5148        (void*) PluginSurfaceReady },
5149    { "nativeValidNodeAndBounds", "(IIILandroid/graphics/Rect;)Z",
5150        (void*) ValidNodeAndBounds },
5151    { "nativeHitTest", "(IIIIZ)Landroid/webkit/WebViewCore$WebKitHitTest;",
5152        (void*) HitTest },
5153    { "nativeAutoFillForm", "(II)V",
5154        (void*) AutoFillForm },
5155    { "nativeScrollLayer", "(IILandroid/graphics/Rect;)V",
5156        (void*) ScrollRenderLayer },
5157    { "nativeCloseIdleConnections", "(I)V",
5158        (void*) CloseIdleConnections },
5159    { "nativeDeleteText", "(IIIII)V",
5160        (void*) DeleteText },
5161    { "nativeInsertText", "(ILjava/lang/String;)V",
5162        (void*) InsertText },
5163    { "nativeGetText", "(IIIII)Ljava/lang/String;",
5164        (void*) GetText },
5165    { "nativeSelectText", "(IIIII)V",
5166        (void*) SelectText },
5167    { "nativeClearTextSelection", "(I)V",
5168        (void*) ClearSelection },
5169    { "nativeSelectWordAt", "(III)V",
5170        (void*) SelectWordAt },
5171    { "nativeSelectAll", "(I)V",
5172        (void*) SelectAll },
5173    { "nativeCertTrustChanged","()V",
5174        (void*) nativeCertTrustChanged },
5175    { "nativeFindAll", "(ILjava/lang/String;)I",
5176        (void*) FindAll },
5177    { "nativeFindNext", "(IZ)V",
5178        (void*) FindNext },
5179};
5180
5181int registerWebViewCore(JNIEnv* env)
5182{
5183    jclass widget = env->FindClass("android/webkit/WebViewCore");
5184    ALOG_ASSERT(widget,
5185            "Unable to find class android/webkit/WebViewCore");
5186    gWebViewCoreFields.m_nativeClass = env->GetFieldID(widget, "mNativeClass",
5187            "I");
5188    ALOG_ASSERT(gWebViewCoreFields.m_nativeClass,
5189            "Unable to find android/webkit/WebViewCore.mNativeClass");
5190    gWebViewCoreFields.m_viewportWidth = env->GetFieldID(widget,
5191            "mViewportWidth", "I");
5192    ALOG_ASSERT(gWebViewCoreFields.m_viewportWidth,
5193            "Unable to find android/webkit/WebViewCore.mViewportWidth");
5194    gWebViewCoreFields.m_viewportHeight = env->GetFieldID(widget,
5195            "mViewportHeight", "I");
5196    ALOG_ASSERT(gWebViewCoreFields.m_viewportHeight,
5197            "Unable to find android/webkit/WebViewCore.mViewportHeight");
5198    gWebViewCoreFields.m_viewportInitialScale = env->GetFieldID(widget,
5199            "mViewportInitialScale", "I");
5200    ALOG_ASSERT(gWebViewCoreFields.m_viewportInitialScale,
5201            "Unable to find android/webkit/WebViewCore.mViewportInitialScale");
5202    gWebViewCoreFields.m_viewportMinimumScale = env->GetFieldID(widget,
5203            "mViewportMinimumScale", "I");
5204    ALOG_ASSERT(gWebViewCoreFields.m_viewportMinimumScale,
5205            "Unable to find android/webkit/WebViewCore.mViewportMinimumScale");
5206    gWebViewCoreFields.m_viewportMaximumScale = env->GetFieldID(widget,
5207            "mViewportMaximumScale", "I");
5208    ALOG_ASSERT(gWebViewCoreFields.m_viewportMaximumScale,
5209            "Unable to find android/webkit/WebViewCore.mViewportMaximumScale");
5210    gWebViewCoreFields.m_viewportUserScalable = env->GetFieldID(widget,
5211            "mViewportUserScalable", "Z");
5212    ALOG_ASSERT(gWebViewCoreFields.m_viewportUserScalable,
5213            "Unable to find android/webkit/WebViewCore.mViewportUserScalable");
5214    gWebViewCoreFields.m_viewportDensityDpi = env->GetFieldID(widget,
5215            "mViewportDensityDpi", "I");
5216    ALOG_ASSERT(gWebViewCoreFields.m_viewportDensityDpi,
5217            "Unable to find android/webkit/WebViewCore.mViewportDensityDpi");
5218    gWebViewCoreFields.m_webView = env->GetFieldID(widget,
5219            "mWebView", "Landroid/webkit/WebView;");
5220    ALOG_ASSERT(gWebViewCoreFields.m_webView,
5221            "Unable to find android/webkit/WebViewCore.mWebView");
5222    gWebViewCoreFields.m_drawIsPaused = env->GetFieldID(widget,
5223            "mDrawIsPaused", "Z");
5224    ALOG_ASSERT(gWebViewCoreFields.m_drawIsPaused,
5225            "Unable to find android/webkit/WebViewCore.mDrawIsPaused");
5226    gWebViewCoreFields.m_lowMemoryUsageMb = env->GetFieldID(widget, "mLowMemoryUsageThresholdMb", "I");
5227    gWebViewCoreFields.m_highMemoryUsageMb = env->GetFieldID(widget, "mHighMemoryUsageThresholdMb", "I");
5228    gWebViewCoreFields.m_highUsageDeltaMb = env->GetFieldID(widget, "mHighUsageDeltaMb", "I");
5229
5230    gWebViewCoreStaticMethods.m_isSupportedMediaMimeType =
5231        env->GetStaticMethodID(widget, "isSupportedMediaMimeType", "(Ljava/lang/String;)Z");
5232    LOG_FATAL_IF(!gWebViewCoreStaticMethods.m_isSupportedMediaMimeType,
5233        "Could not find static method isSupportedMediaMimeType from WebViewCore");
5234
5235    env->DeleteLocalRef(widget);
5236
5237    return jniRegisterNativeMethods(env, "android/webkit/WebViewCore",
5238            gJavaWebViewCoreMethods, NELEM(gJavaWebViewCoreMethods));
5239}
5240
5241} /* namespace android */
5242