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