WebViewCore.cpp revision 1045cce1e3570e0eba94274e8960e1ed7a2335d0
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 start = firstPositionInNode(node);
3659        Position end = lastPositionInNode(node);
3660        VisibleSelection allEditableText(start, end);
3661        if (allEditableText.isRange())
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        if (selection.isRange()) {
4202            PassRefPtr<Range> range = selection.firstRange();
4203            String textInRange = range->text();
4204            if (textInRange.length() > 0) {
4205                if (text.length() > 0)
4206                    text.append('\n');
4207                text.append(textInRange);
4208            }
4209        }
4210    }
4211
4212    return text;
4213}
4214
4215//----------------------------------------------------------------------
4216// Native JNI methods
4217//----------------------------------------------------------------------
4218static void RevealSelection(JNIEnv* env, jobject obj, jint nativeClass)
4219{
4220    reinterpret_cast<WebViewCore*>(nativeClass)->revealSelection();
4221}
4222
4223static jstring RequestLabel(JNIEnv* env, jobject obj, jint nativeClass,
4224        int framePointer, int nodePointer)
4225{
4226    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4227    return wtfStringToJstring(env, viewImpl->requestLabel(
4228            (WebCore::Frame*) framePointer, (WebCore::Node*) nodePointer));
4229}
4230
4231static void ClearContent(JNIEnv* env, jobject obj, jint nativeClass)
4232{
4233    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4234    viewImpl->clearContent();
4235}
4236
4237static void UpdateFrameCacheIfLoading(JNIEnv* env, jobject obj, jint nativeClass)
4238{
4239}
4240
4241static void SetSize(JNIEnv* env, jobject obj, jint nativeClass, jint width,
4242        jint height, jint textWrapWidth, jfloat scale, jint screenWidth,
4243        jint screenHeight, jint anchorX, jint anchorY, jboolean ignoreHeight)
4244{
4245    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4246    ALOGV("webviewcore::nativeSetSize(%u %u)\n viewImpl: %p", (unsigned)width, (unsigned)height, viewImpl);
4247    ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSetSize");
4248    viewImpl->setSizeScreenWidthAndScale(width, height, textWrapWidth, scale,
4249            screenWidth, screenHeight, anchorX, anchorY, ignoreHeight);
4250}
4251
4252static void SetScrollOffset(JNIEnv* env, jobject obj, jint nativeClass,
4253        jint gen, jboolean sendScrollEvent, jint x, jint y)
4254{
4255    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4256    ALOG_ASSERT(viewImpl, "need viewImpl");
4257
4258    viewImpl->setScrollOffset(gen, sendScrollEvent, x, y);
4259}
4260
4261static void SetGlobalBounds(JNIEnv* env, jobject obj, jint nativeClass,
4262        jint x, jint y, jint h, jint v)
4263{
4264    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4265    ALOG_ASSERT(viewImpl, "need viewImpl");
4266
4267    viewImpl->setGlobalBounds(x, y, h, v);
4268}
4269
4270static jboolean Key(JNIEnv* env, jobject obj, jint nativeClass, jint keyCode,
4271        jint unichar, jint repeatCount, jboolean isShift, jboolean isAlt,
4272        jboolean isSym, jboolean isDown)
4273{
4274    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4275    return viewImpl->key(PlatformKeyboardEvent(keyCode,
4276        unichar, repeatCount, isDown, isShift, isAlt, isSym));
4277}
4278
4279static void Click(JNIEnv* env, jobject obj, jint nativeClass, int framePtr,
4280        int nodePtr, jboolean fake)
4281{
4282    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4283    ALOG_ASSERT(viewImpl, "viewImpl not set in Click");
4284
4285    viewImpl->click(reinterpret_cast<WebCore::Frame*>(framePtr),
4286        reinterpret_cast<WebCore::Node*>(nodePtr), fake);
4287}
4288
4289static void ContentInvalidateAll(JNIEnv* env, jobject obj, jint nativeClass)
4290{
4291    reinterpret_cast<WebViewCore*>(nativeClass)->contentInvalidateAll();
4292}
4293
4294static void DeleteSelection(JNIEnv* env, jobject obj, jint nativeClass,
4295        jint start, jint end, jint textGeneration)
4296{
4297    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4298    viewImpl->deleteSelection(start, end, textGeneration);
4299}
4300
4301static void SetSelection(JNIEnv* env, jobject obj, jint nativeClass,
4302        jint start, jint end)
4303{
4304    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4305    viewImpl->setSelection(start, end);
4306}
4307
4308static jstring ModifySelection(JNIEnv* env, jobject obj, jint nativeClass,
4309        jint direction, jint granularity)
4310{
4311    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4312    String selectionString = viewImpl->modifySelection(direction, granularity);
4313    return wtfStringToJstring(env, selectionString);
4314}
4315
4316static void ReplaceTextfieldText(JNIEnv* env, jobject obj, jint nativeClass,
4317    jint oldStart, jint oldEnd, jstring replace, jint start, jint end,
4318    jint textGeneration)
4319{
4320    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4321    WTF::String webcoreString = jstringToWtfString(env, replace);
4322    viewImpl->replaceTextfieldText(oldStart,
4323            oldEnd, webcoreString, start, end, textGeneration);
4324}
4325
4326static void PassToJs(JNIEnv* env, jobject obj, jint nativeClass,
4327    jint generation, jstring currentText, jint keyCode,
4328    jint keyValue, jboolean down, jboolean cap, jboolean fn, jboolean sym)
4329{
4330    WTF::String current = jstringToWtfString(env, currentText);
4331    reinterpret_cast<WebViewCore*>(nativeClass)->passToJs(generation, current,
4332        PlatformKeyboardEvent(keyCode, keyValue, 0, down, cap, fn, sym));
4333}
4334
4335static void ScrollFocusedTextInput(JNIEnv* env, jobject obj, jint nativeClass,
4336        jfloat xPercent, jint y)
4337{
4338    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4339    viewImpl->scrollFocusedTextInput(xPercent, y);
4340}
4341
4342static void SetFocusControllerActive(JNIEnv* env, jobject obj, jint nativeClass,
4343        jboolean active)
4344{
4345    ALOGV("webviewcore::nativeSetFocusControllerActive()\n");
4346    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4347    ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSetFocusControllerActive");
4348    viewImpl->setFocusControllerActive(active);
4349}
4350
4351static void SaveDocumentState(JNIEnv* env, jobject obj, jint nativeClass,
4352        jint frame)
4353{
4354    ALOGV("webviewcore::nativeSaveDocumentState()\n");
4355    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4356    ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSaveDocumentState");
4357    viewImpl->saveDocumentState((WebCore::Frame*) frame);
4358}
4359
4360void WebViewCore::addVisitedLink(const UChar* string, int length)
4361{
4362    if (m_groupForVisitedLinks)
4363        m_groupForVisitedLinks->addVisitedLink(string, length);
4364}
4365
4366static bool UpdateLayers(JNIEnv* env, jobject obj, jint nativeClass,
4367        jint jbaseLayer)
4368{
4369    WebViewCore* viewImpl = (WebViewCore*) nativeClass;
4370    BaseLayerAndroid* baseLayer = (BaseLayerAndroid*)  jbaseLayer;
4371    if (baseLayer) {
4372        LayerAndroid* root = static_cast<LayerAndroid*>(baseLayer->getChild(0));
4373        if (root)
4374            return viewImpl->updateLayers(root);
4375    }
4376    return true;
4377}
4378
4379static void NotifyAnimationStarted(JNIEnv* env, jobject obj, jint nativeClass)
4380{
4381    WebViewCore* viewImpl = (WebViewCore*) nativeClass;
4382    viewImpl->notifyAnimationStarted();
4383}
4384
4385static jint RecordContent(JNIEnv* env, jobject obj, jint nativeClass,
4386        jobject region, jobject pt)
4387{
4388    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4389    SkRegion* nativeRegion = GraphicsJNI::getNativeRegion(env, region);
4390    SkIPoint nativePt;
4391    BaseLayerAndroid* result = viewImpl->recordContent(nativeRegion, &nativePt);
4392    GraphicsJNI::ipoint_to_jpoint(nativePt, env, pt);
4393    return reinterpret_cast<jint>(result);
4394}
4395
4396static void SplitContent(JNIEnv* env, jobject obj, jint nativeClass,
4397        jint content)
4398{
4399    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4400    viewImpl->splitContent(reinterpret_cast<PictureSet*>(content));
4401}
4402
4403static void SendListBoxChoice(JNIEnv* env, jobject obj, jint nativeClass,
4404        jint choice)
4405{
4406    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4407    ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoice");
4408    viewImpl->popupReply(choice);
4409}
4410
4411// Set aside a predetermined amount of space in which to place the listbox
4412// choices, to avoid unnecessary allocations.
4413// The size here is arbitrary.  We want the size to be at least as great as the
4414// number of items in the average multiple-select listbox.
4415#define PREPARED_LISTBOX_STORAGE 10
4416
4417static void SendListBoxChoices(JNIEnv* env, jobject obj, jint nativeClass,
4418        jbooleanArray jArray, jint size)
4419{
4420    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4421    ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoices");
4422    jboolean* ptrArray = env->GetBooleanArrayElements(jArray, 0);
4423    SkAutoSTMalloc<PREPARED_LISTBOX_STORAGE, int> storage(size);
4424    int* array = storage.get();
4425    int count = 0;
4426    for (int i = 0; i < size; i++) {
4427        if (ptrArray[i]) {
4428            array[count++] = i;
4429        }
4430    }
4431    env->ReleaseBooleanArrayElements(jArray, ptrArray, JNI_ABORT);
4432    viewImpl->popupReply(array, count);
4433}
4434
4435// TODO: Move this to WebView.cpp since it is only needed there
4436static jstring FindAddress(JNIEnv* env, jobject obj, jstring addr,
4437        jboolean caseInsensitive)
4438{
4439    if (!addr)
4440        return 0;
4441    int length = env->GetStringLength(addr);
4442    if (!length)
4443        return 0;
4444    const jchar* addrChars = env->GetStringChars(addr, 0);
4445    size_t start, end;
4446    AddressDetector detector;
4447    bool success = detector.FindContent(addrChars, addrChars + length, &start, &end);
4448    jstring ret = 0;
4449    if (success)
4450        ret = env->NewString(addrChars + start, end - start);
4451    env->ReleaseStringChars(addr, addrChars);
4452    return ret;
4453}
4454
4455static jboolean HandleTouchEvent(JNIEnv* env, jobject obj, jint nativeClass,
4456        jint action, jintArray idArray, jintArray xArray, jintArray yArray,
4457        jint count, jint actionIndex, jint metaState)
4458{
4459    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4460    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4461    jint* ptrIdArray = env->GetIntArrayElements(idArray, 0);
4462    jint* ptrXArray = env->GetIntArrayElements(xArray, 0);
4463    jint* ptrYArray = env->GetIntArrayElements(yArray, 0);
4464    Vector<int> ids(count);
4465    Vector<IntPoint> points(count);
4466    for (int c = 0; c < count; c++) {
4467        ids[c] = ptrIdArray[c];
4468        points[c].setX(ptrXArray[c]);
4469        points[c].setY(ptrYArray[c]);
4470    }
4471    env->ReleaseIntArrayElements(idArray, ptrIdArray, JNI_ABORT);
4472    env->ReleaseIntArrayElements(xArray, ptrXArray, JNI_ABORT);
4473    env->ReleaseIntArrayElements(yArray, ptrYArray, JNI_ABORT);
4474
4475    return viewImpl->handleTouchEvent(action, ids, points, actionIndex, metaState);
4476}
4477
4478static void TouchUp(JNIEnv* env, jobject obj, jint nativeClass,
4479        jint touchGeneration, jint frame, jint node, jint x, jint y)
4480{
4481    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4482    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4483    viewImpl->touchUp(touchGeneration,
4484        (WebCore::Frame*) frame, (WebCore::Node*) node, x, y);
4485}
4486
4487static jstring RetrieveHref(JNIEnv* env, jobject obj, jint nativeClass,
4488        jint x, jint y)
4489{
4490    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4491    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4492    WTF::String result = viewImpl->retrieveHref(x, y);
4493    if (!result.isEmpty())
4494        return wtfStringToJstring(env, result);
4495    return 0;
4496}
4497
4498static jstring RetrieveAnchorText(JNIEnv* env, jobject obj, jint nativeClass,
4499        jint x, jint y)
4500{
4501    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4502    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4503    WTF::String result = viewImpl->retrieveAnchorText(x, y);
4504    if (!result.isEmpty())
4505        return wtfStringToJstring(env, result);
4506    return 0;
4507}
4508
4509static jstring RetrieveImageSource(JNIEnv* env, jobject obj, jint nativeClass,
4510        jint x, jint y)
4511{
4512    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4513    WTF::String result = viewImpl->retrieveImageSource(x, y);
4514    return !result.isEmpty() ? wtfStringToJstring(env, result) : 0;
4515}
4516
4517static void MoveFocus(JNIEnv* env, jobject obj, jint nativeClass, jint framePtr,
4518        jint nodePtr)
4519{
4520    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4521    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4522    viewImpl->moveFocus((WebCore::Frame*) framePtr, (WebCore::Node*) nodePtr);
4523}
4524
4525static void MoveMouse(JNIEnv* env, jobject obj, jint nativeClass, jint frame,
4526        jint x, jint y)
4527{
4528    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4529    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4530    viewImpl->moveMouse((WebCore::Frame*) frame, x, y);
4531}
4532
4533static void MoveMouseIfLatest(JNIEnv* env, jobject obj, jint nativeClass,
4534        jint moveGeneration, jint frame, jint x, jint y)
4535{
4536    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4537    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4538    viewImpl->moveMouseIfLatest(moveGeneration,
4539        (WebCore::Frame*) frame, x, y);
4540}
4541
4542static void UpdateFrameCache(JNIEnv* env, jobject obj, jint nativeClass)
4543{
4544}
4545
4546static jint GetContentMinPrefWidth(JNIEnv* env, jobject obj, jint nativeClass)
4547{
4548    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4549    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4550
4551    WebCore::Frame* frame = viewImpl->mainFrame();
4552    if (frame) {
4553        WebCore::Document* document = frame->document();
4554        if (document) {
4555            WebCore::RenderObject* renderer = document->renderer();
4556            if (renderer && renderer->isRenderView()) {
4557                return renderer->minPreferredLogicalWidth();
4558            }
4559        }
4560    }
4561    return 0;
4562}
4563
4564static void SetViewportSettingsFromNative(JNIEnv* env, jobject obj,
4565        jint nativeClass)
4566{
4567    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4568    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4569
4570    WebCore::Settings* s = viewImpl->mainFrame()->page()->settings();
4571    if (!s)
4572        return;
4573
4574#ifdef ANDROID_META_SUPPORT
4575    env->SetIntField(obj, gWebViewCoreFields.m_viewportWidth, s->viewportWidth());
4576    env->SetIntField(obj, gWebViewCoreFields.m_viewportHeight, s->viewportHeight());
4577    env->SetIntField(obj, gWebViewCoreFields.m_viewportInitialScale, s->viewportInitialScale());
4578    env->SetIntField(obj, gWebViewCoreFields.m_viewportMinimumScale, s->viewportMinimumScale());
4579    env->SetIntField(obj, gWebViewCoreFields.m_viewportMaximumScale, s->viewportMaximumScale());
4580    env->SetBooleanField(obj, gWebViewCoreFields.m_viewportUserScalable, s->viewportUserScalable());
4581    env->SetIntField(obj, gWebViewCoreFields.m_viewportDensityDpi, s->viewportTargetDensityDpi());
4582#endif
4583}
4584
4585static void SetBackgroundColor(JNIEnv* env, jobject obj, jint nativeClass,
4586        jint color)
4587{
4588    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4589    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4590
4591    viewImpl->setBackgroundColor((SkColor) color);
4592}
4593
4594static void DumpDomTree(JNIEnv* env, jobject obj, jint nativeClass,
4595        jboolean useFile)
4596{
4597    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4598    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4599
4600    viewImpl->dumpDomTree(useFile);
4601}
4602
4603static void DumpRenderTree(JNIEnv* env, jobject obj, jint nativeClass,
4604        jboolean useFile)
4605{
4606    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4607    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4608
4609    viewImpl->dumpRenderTree(useFile);
4610}
4611
4612static void DumpNavTree(JNIEnv* env, jobject obj, jint nativeClass)
4613{
4614}
4615
4616static void SetJsFlags(JNIEnv* env, jobject obj, jint nativeClass, jstring flags)
4617{
4618    WTF::String flagsString = jstringToWtfString(env, flags);
4619    WTF::CString utf8String = flagsString.utf8();
4620    WebCore::ScriptController::setFlags(utf8String.data(), utf8String.length());
4621}
4622
4623
4624// Called from the Java side to set a new quota for the origin or new appcache
4625// max size in response to a notification that the original quota was exceeded or
4626// that the appcache has reached its maximum size.
4627static void SetNewStorageLimit(JNIEnv* env, jobject obj, jint nativeClass,
4628        jlong quota)
4629{
4630#if ENABLE(DATABASE) || ENABLE(OFFLINE_WEB_APPLICATIONS)
4631    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4632    Frame* frame = viewImpl->mainFrame();
4633
4634    // The main thread is blocked awaiting this response, so now we can wake it
4635    // up.
4636    ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client());
4637    chromeC->wakeUpMainThreadWithNewQuota(quota);
4638#endif
4639}
4640
4641// Called from Java to provide a Geolocation permission state for the specified origin.
4642static void GeolocationPermissionsProvide(JNIEnv* env, jobject obj,
4643        jint nativeClass, jstring origin, jboolean allow, jboolean remember)
4644{
4645    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4646    Frame* frame = viewImpl->mainFrame();
4647
4648    ChromeClientAndroid* chromeClient = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client());
4649    chromeClient->provideGeolocationPermissions(jstringToWtfString(env, origin), allow, remember);
4650}
4651
4652static void RegisterURLSchemeAsLocal(JNIEnv* env, jobject obj, jint nativeClass,
4653        jstring scheme)
4654{
4655    WebCore::SchemeRegistry::registerURLSchemeAsLocal(jstringToWtfString(env, scheme));
4656}
4657
4658static bool FocusBoundsChanged(JNIEnv* env, jobject obj, jint nativeClass)
4659{
4660    return reinterpret_cast<WebViewCore*>(nativeClass)->focusBoundsChanged();
4661}
4662
4663static void SetIsPaused(JNIEnv* env, jobject obj, jint nativeClass,
4664        jboolean isPaused)
4665{
4666    // tell the webcore thread to stop thinking while we do other work
4667    // (selection and scrolling). This has nothing to do with the lifecycle
4668    // pause and resume.
4669    reinterpret_cast<WebViewCore*>(nativeClass)->setIsPaused(isPaused);
4670}
4671
4672static void Pause(JNIEnv* env, jobject obj, jint nativeClass)
4673{
4674    // This is called for the foreground tab when the browser is put to the
4675    // background (and also for any tab when it is put to the background of the
4676    // browser). The browser can only be killed by the system when it is in the
4677    // background, so saving the Geolocation permission state now ensures that
4678    // is maintained when the browser is killed.
4679    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4680    ChromeClient* chromeClient = viewImpl->mainFrame()->page()->chrome()->client();
4681    ChromeClientAndroid* chromeClientAndroid = static_cast<ChromeClientAndroid*>(chromeClient);
4682    chromeClientAndroid->storeGeolocationPermissions();
4683
4684    Frame* mainFrame = viewImpl->mainFrame();
4685    for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) {
4686        Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation();
4687        if (geolocation)
4688            geolocation->suspend();
4689    }
4690
4691    viewImpl->deviceMotionAndOrientationManager()->maybeSuspendClients();
4692
4693    ANPEvent event;
4694    SkANP::InitEvent(&event, kLifecycle_ANPEventType);
4695    event.data.lifecycle.action = kPause_ANPLifecycleAction;
4696    viewImpl->sendPluginEvent(event);
4697
4698    viewImpl->setIsPaused(true);
4699}
4700
4701static void Resume(JNIEnv* env, jobject obj, jint nativeClass)
4702{
4703    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4704    Frame* mainFrame = viewImpl->mainFrame();
4705    for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) {
4706        Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation();
4707        if (geolocation)
4708            geolocation->resume();
4709    }
4710
4711    viewImpl->deviceMotionAndOrientationManager()->maybeResumeClients();
4712
4713    ANPEvent event;
4714    SkANP::InitEvent(&event, kLifecycle_ANPEventType);
4715    event.data.lifecycle.action = kResume_ANPLifecycleAction;
4716    viewImpl->sendPluginEvent(event);
4717
4718    viewImpl->setIsPaused(false);
4719}
4720
4721static void FreeMemory(JNIEnv* env, jobject obj, jint nativeClass)
4722{
4723    ANPEvent event;
4724    SkANP::InitEvent(&event, kLifecycle_ANPEventType);
4725    event.data.lifecycle.action = kFreeMemory_ANPLifecycleAction;
4726    reinterpret_cast<WebViewCore*>(nativeClass)->sendPluginEvent(event);
4727}
4728
4729static void ProvideVisitedHistory(JNIEnv* env, jobject obj, jint nativeClass,
4730        jobject hist)
4731{
4732    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4733    ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4734
4735    jobjectArray array = static_cast<jobjectArray>(hist);
4736
4737    jsize len = env->GetArrayLength(array);
4738    for (jsize i = 0; i < len; i++) {
4739        jstring item = static_cast<jstring>(env->GetObjectArrayElement(array, i));
4740        const UChar* str = static_cast<const UChar*>(env->GetStringChars(item, 0));
4741        jsize len = env->GetStringLength(item);
4742        viewImpl->addVisitedLink(str, len);
4743        env->ReleaseStringChars(item, str);
4744        env->DeleteLocalRef(item);
4745    }
4746}
4747
4748static void PluginSurfaceReady(JNIEnv* env, jobject obj, jint nativeClass)
4749{
4750    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4751    if (viewImpl)
4752        viewImpl->sendPluginSurfaceReady();
4753}
4754
4755// Notification from the UI thread that the plugin's full-screen surface has been discarded
4756static void FullScreenPluginHidden(JNIEnv* env, jobject obj, jint nativeClass,
4757        jint npp)
4758{
4759    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4760    PluginWidgetAndroid* plugin = viewImpl->getPluginWidget((NPP)npp);
4761    if (plugin)
4762        plugin->exitFullScreen(false);
4763}
4764
4765static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj)
4766{
4767    int L, T, R, B;
4768    GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B);
4769    return WebCore::IntRect(L, T, R - L, B - T);
4770}
4771
4772static bool ValidNodeAndBounds(JNIEnv* env, jobject obj, jint nativeClass,
4773        int frame, int node, jobject rect)
4774{
4775    IntRect nativeRect = jrect_to_webrect(env, rect);
4776    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4777    return viewImpl->validNodeAndBounds(
4778            reinterpret_cast<Frame*>(frame),
4779            reinterpret_cast<Node*>(node), nativeRect);
4780}
4781
4782static jobject HitTest(JNIEnv* env, jobject obj, jint nativeClass, jint x,
4783                       jint y, jint slop, jboolean doMoveMouse)
4784{
4785    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4786    if (!viewImpl)
4787        return 0;
4788    AndroidHitTestResult result = viewImpl->hitTestAtPoint(x, y, slop, doMoveMouse);
4789    return result.createJavaObject(env);
4790}
4791
4792static void AutoFillForm(JNIEnv* env, jobject obj, jint nativeClass,
4793        jint queryId)
4794{
4795#if ENABLE(WEB_AUTOFILL)
4796    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4797    if (!viewImpl)
4798        return;
4799
4800    WebCore::Frame* frame = viewImpl->mainFrame();
4801    if (frame) {
4802        EditorClientAndroid* editorC = static_cast<EditorClientAndroid*>(frame->page()->editorClient());
4803        WebAutofill* autoFill = editorC->getAutofill();
4804        autoFill->fillFormFields(queryId);
4805    }
4806#endif
4807}
4808
4809static void CloseIdleConnections(JNIEnv* env, jobject obj, jint nativeClass)
4810{
4811    WebCache::get(true)->closeIdleConnections();
4812    WebCache::get(false)->closeIdleConnections();
4813}
4814
4815static void nativeCertTrustChanged(JNIEnv *env, jobject obj)
4816{
4817#if USE(CHROME_NETWORK_STACK)
4818    WebCache::get(true)->certTrustChanged();
4819    WebCache::get(false)->certTrustChanged();
4820#endif
4821}
4822
4823static void ScrollRenderLayer(JNIEnv* env, jobject obj, jint nativeClass,
4824        jint layer, jobject jRect)
4825{
4826    SkRect rect;
4827    GraphicsJNI::jrect_to_rect(env, jRect, &rect);
4828    reinterpret_cast<WebViewCore*>(nativeClass)->scrollRenderLayer(layer, rect);
4829}
4830
4831static void DeleteText(JNIEnv* env, jobject obj, jint nativeClass,
4832        jint startX, jint startY, jint endX, jint endY)
4833{
4834    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4835    viewImpl->deleteText(startX, startY, endX, endY);
4836}
4837
4838static void InsertText(JNIEnv* env, jobject obj, jint nativeClass,
4839        jstring text)
4840{
4841    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4842    WTF::String wtfText = jstringToWtfString(env, text);
4843    viewImpl->insertText(wtfText);
4844}
4845
4846static jobject GetText(JNIEnv* env, jobject obj, jint nativeClass,
4847        jint startX, jint startY, jint endX, jint endY)
4848{
4849    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4850    WTF::String text = viewImpl->getText(startX, startY, endX, endY);
4851    return text.isEmpty() ? 0 : wtfStringToJstring(env, text);
4852}
4853
4854static void SelectText(JNIEnv* env, jobject obj, jint nativeClass,
4855        jint startX, jint startY, jint endX, jint endY)
4856{
4857    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4858    viewImpl->selectText(startX, startY, endX, endY);
4859}
4860
4861static void ClearSelection(JNIEnv* env, jobject obj, jint nativeClass)
4862{
4863    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4864    viewImpl->focusedFrame()->selection()->clear();
4865}
4866
4867static void SelectWordAt(JNIEnv* env, jobject obj, jint nativeClass, jint x, jint y)
4868{
4869    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4870    viewImpl->selectWordAt(x, y);
4871}
4872
4873static void SelectAll(JNIEnv* env, jobject obj, jint nativeClass)
4874{
4875    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4876    viewImpl->focusedFrame()->selection()->selectAll();
4877}
4878
4879static int FindAll(JNIEnv* env, jobject obj, jint nativeClass,
4880        jstring text)
4881{
4882    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4883    WTF::String wtfText = jstringToWtfString(env, text);
4884    return viewImpl->findTextOnPage(wtfText);
4885}
4886
4887static void FindNext(JNIEnv* env, jobject obj, jint nativeClass,
4888        jboolean forward)
4889{
4890    WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
4891    viewImpl->findNextOnPage(forward);
4892}
4893
4894// ----------------------------------------------------------------------------
4895
4896/*
4897 * JNI registration.
4898 */
4899static JNINativeMethod gJavaWebViewCoreMethods[] = {
4900    { "nativeClearContent", "(I)V",
4901            (void*) ClearContent },
4902    { "nativeFocusBoundsChanged", "(I)Z",
4903        (void*) FocusBoundsChanged } ,
4904    { "nativeKey", "(IIIIZZZZ)Z",
4905        (void*) Key },
4906    { "nativeClick", "(IIIZ)V",
4907        (void*) Click },
4908    { "nativeContentInvalidateAll", "(I)V",
4909        (void*) ContentInvalidateAll },
4910    { "nativeSendListBoxChoices", "(I[ZI)V",
4911        (void*) SendListBoxChoices },
4912    { "nativeSendListBoxChoice", "(II)V",
4913        (void*) SendListBoxChoice },
4914    { "nativeSetSize", "(IIIIFIIIIZ)V",
4915        (void*) SetSize },
4916    { "nativeSetScrollOffset", "(IIZII)V",
4917        (void*) SetScrollOffset },
4918    { "nativeSetGlobalBounds", "(IIIII)V",
4919        (void*) SetGlobalBounds },
4920    { "nativeSetSelection", "(III)V",
4921        (void*) SetSelection } ,
4922    { "nativeModifySelection", "(III)Ljava/lang/String;",
4923        (void*) ModifySelection },
4924    { "nativeDeleteSelection", "(IIII)V",
4925        (void*) DeleteSelection } ,
4926    { "nativeReplaceTextfieldText", "(IIILjava/lang/String;III)V",
4927        (void*) ReplaceTextfieldText } ,
4928    { "nativeMoveFocus", "(III)V",
4929        (void*) MoveFocus },
4930    { "nativeMoveMouse", "(IIII)V",
4931        (void*) MoveMouse },
4932    { "nativeMoveMouseIfLatest", "(IIIII)V",
4933        (void*) MoveMouseIfLatest },
4934    { "passToJs", "(IILjava/lang/String;IIZZZZ)V",
4935        (void*) PassToJs },
4936    { "nativeScrollFocusedTextInput", "(IFI)V",
4937        (void*) ScrollFocusedTextInput },
4938    { "nativeSetFocusControllerActive", "(IZ)V",
4939        (void*) SetFocusControllerActive },
4940    { "nativeSaveDocumentState", "(II)V",
4941        (void*) SaveDocumentState },
4942    { "nativeFindAddress", "(Ljava/lang/String;Z)Ljava/lang/String;",
4943        (void*) FindAddress },
4944    { "nativeHandleTouchEvent", "(II[I[I[IIII)Z",
4945            (void*) HandleTouchEvent },
4946    { "nativeTouchUp", "(IIIIII)V",
4947        (void*) TouchUp },
4948    { "nativeRetrieveHref", "(III)Ljava/lang/String;",
4949        (void*) RetrieveHref },
4950    { "nativeRetrieveAnchorText", "(III)Ljava/lang/String;",
4951        (void*) RetrieveAnchorText },
4952    { "nativeRetrieveImageSource", "(III)Ljava/lang/String;",
4953        (void*) RetrieveImageSource },
4954    { "nativeUpdateFrameCache", "(I)V",
4955        (void*) UpdateFrameCache },
4956    { "nativeGetContentMinPrefWidth", "(I)I",
4957        (void*) GetContentMinPrefWidth },
4958    { "nativeUpdateLayers", "(II)Z",
4959        (void*) UpdateLayers },
4960    { "nativeNotifyAnimationStarted", "(I)V",
4961        (void*) NotifyAnimationStarted },
4962    { "nativeRecordContent", "(ILandroid/graphics/Region;Landroid/graphics/Point;)I",
4963        (void*) RecordContent },
4964    { "setViewportSettingsFromNative", "(I)V",
4965        (void*) SetViewportSettingsFromNative },
4966    { "nativeSplitContent", "(II)V",
4967        (void*) SplitContent },
4968    { "nativeSetBackgroundColor", "(II)V",
4969        (void*) SetBackgroundColor },
4970    { "nativeRegisterURLSchemeAsLocal", "(ILjava/lang/String;)V",
4971        (void*) RegisterURLSchemeAsLocal },
4972    { "nativeDumpDomTree", "(IZ)V",
4973        (void*) DumpDomTree },
4974    { "nativeDumpRenderTree", "(IZ)V",
4975        (void*) DumpRenderTree },
4976    { "nativeDumpNavTree", "(I)V",
4977        (void*) DumpNavTree },
4978    { "nativeSetNewStorageLimit", "(IJ)V",
4979        (void*) SetNewStorageLimit },
4980    { "nativeGeolocationPermissionsProvide", "(ILjava/lang/String;ZZ)V",
4981        (void*) GeolocationPermissionsProvide },
4982    { "nativeSetIsPaused", "(IZ)V", (void*) SetIsPaused },
4983    { "nativePause", "(I)V", (void*) Pause },
4984    { "nativeResume", "(I)V", (void*) Resume },
4985    { "nativeFreeMemory", "(I)V", (void*) FreeMemory },
4986    { "nativeSetJsFlags", "(ILjava/lang/String;)V", (void*) SetJsFlags },
4987    { "nativeRequestLabel", "(III)Ljava/lang/String;",
4988        (void*) RequestLabel },
4989    { "nativeRevealSelection", "(I)V", (void*) RevealSelection },
4990    { "nativeUpdateFrameCacheIfLoading", "(I)V",
4991        (void*) UpdateFrameCacheIfLoading },
4992    { "nativeProvideVisitedHistory", "(I[Ljava/lang/String;)V",
4993        (void*) ProvideVisitedHistory },
4994    { "nativeFullScreenPluginHidden", "(II)V",
4995        (void*) FullScreenPluginHidden },
4996    { "nativePluginSurfaceReady", "(I)V",
4997        (void*) PluginSurfaceReady },
4998    { "nativeValidNodeAndBounds", "(IIILandroid/graphics/Rect;)Z",
4999        (void*) ValidNodeAndBounds },
5000    { "nativeHitTest", "(IIIIZ)Landroid/webkit/WebViewCore$WebKitHitTest;",
5001        (void*) HitTest },
5002    { "nativeAutoFillForm", "(II)V",
5003        (void*) AutoFillForm },
5004    { "nativeScrollLayer", "(IILandroid/graphics/Rect;)V",
5005        (void*) ScrollRenderLayer },
5006    { "nativeCloseIdleConnections", "(I)V",
5007        (void*) CloseIdleConnections },
5008    { "nativeDeleteText", "(IIIII)V",
5009        (void*) DeleteText },
5010    { "nativeInsertText", "(ILjava/lang/String;)V",
5011        (void*) InsertText },
5012    { "nativeGetText", "(IIIII)Ljava/lang/String;",
5013        (void*) GetText },
5014    { "nativeSelectText", "(IIIII)V",
5015        (void*) SelectText },
5016    { "nativeClearTextSelection", "(I)V",
5017        (void*) ClearSelection },
5018    { "nativeSelectWordAt", "(III)V",
5019        (void*) SelectWordAt },
5020    { "nativeSelectAll", "(I)V",
5021        (void*) SelectAll },
5022    { "nativeCertTrustChanged","()V",
5023        (void*) nativeCertTrustChanged },
5024    { "nativeFindAll", "(ILjava/lang/String;)I",
5025        (void*) FindAll },
5026    { "nativeFindNext", "(IZ)V",
5027        (void*) FindNext },
5028};
5029
5030int registerWebViewCore(JNIEnv* env)
5031{
5032    jclass widget = env->FindClass("android/webkit/WebViewCore");
5033    ALOG_ASSERT(widget,
5034            "Unable to find class android/webkit/WebViewCore");
5035    gWebViewCoreFields.m_nativeClass = env->GetFieldID(widget, "mNativeClass",
5036            "I");
5037    ALOG_ASSERT(gWebViewCoreFields.m_nativeClass,
5038            "Unable to find android/webkit/WebViewCore.mNativeClass");
5039    gWebViewCoreFields.m_viewportWidth = env->GetFieldID(widget,
5040            "mViewportWidth", "I");
5041    ALOG_ASSERT(gWebViewCoreFields.m_viewportWidth,
5042            "Unable to find android/webkit/WebViewCore.mViewportWidth");
5043    gWebViewCoreFields.m_viewportHeight = env->GetFieldID(widget,
5044            "mViewportHeight", "I");
5045    ALOG_ASSERT(gWebViewCoreFields.m_viewportHeight,
5046            "Unable to find android/webkit/WebViewCore.mViewportHeight");
5047    gWebViewCoreFields.m_viewportInitialScale = env->GetFieldID(widget,
5048            "mViewportInitialScale", "I");
5049    ALOG_ASSERT(gWebViewCoreFields.m_viewportInitialScale,
5050            "Unable to find android/webkit/WebViewCore.mViewportInitialScale");
5051    gWebViewCoreFields.m_viewportMinimumScale = env->GetFieldID(widget,
5052            "mViewportMinimumScale", "I");
5053    ALOG_ASSERT(gWebViewCoreFields.m_viewportMinimumScale,
5054            "Unable to find android/webkit/WebViewCore.mViewportMinimumScale");
5055    gWebViewCoreFields.m_viewportMaximumScale = env->GetFieldID(widget,
5056            "mViewportMaximumScale", "I");
5057    ALOG_ASSERT(gWebViewCoreFields.m_viewportMaximumScale,
5058            "Unable to find android/webkit/WebViewCore.mViewportMaximumScale");
5059    gWebViewCoreFields.m_viewportUserScalable = env->GetFieldID(widget,
5060            "mViewportUserScalable", "Z");
5061    ALOG_ASSERT(gWebViewCoreFields.m_viewportUserScalable,
5062            "Unable to find android/webkit/WebViewCore.mViewportUserScalable");
5063    gWebViewCoreFields.m_viewportDensityDpi = env->GetFieldID(widget,
5064            "mViewportDensityDpi", "I");
5065    ALOG_ASSERT(gWebViewCoreFields.m_viewportDensityDpi,
5066            "Unable to find android/webkit/WebViewCore.mViewportDensityDpi");
5067    gWebViewCoreFields.m_webView = env->GetFieldID(widget,
5068            "mWebView", "Landroid/webkit/WebViewClassic;");
5069    ALOG_ASSERT(gWebViewCoreFields.m_webView,
5070            "Unable to find android/webkit/WebViewCore.mWebView");
5071    gWebViewCoreFields.m_drawIsPaused = env->GetFieldID(widget,
5072            "mDrawIsPaused", "Z");
5073    ALOG_ASSERT(gWebViewCoreFields.m_drawIsPaused,
5074            "Unable to find android/webkit/WebViewCore.mDrawIsPaused");
5075    gWebViewCoreFields.m_lowMemoryUsageMb = env->GetFieldID(widget, "mLowMemoryUsageThresholdMb", "I");
5076    gWebViewCoreFields.m_highMemoryUsageMb = env->GetFieldID(widget, "mHighMemoryUsageThresholdMb", "I");
5077    gWebViewCoreFields.m_highUsageDeltaMb = env->GetFieldID(widget, "mHighUsageDeltaMb", "I");
5078
5079    gWebViewCoreStaticMethods.m_isSupportedMediaMimeType =
5080        env->GetStaticMethodID(widget, "isSupportedMediaMimeType", "(Ljava/lang/String;)Z");
5081    LOG_FATAL_IF(!gWebViewCoreStaticMethods.m_isSupportedMediaMimeType,
5082        "Could not find static method isSupportedMediaMimeType from WebViewCore");
5083
5084    env->DeleteLocalRef(widget);
5085
5086    return jniRegisterNativeMethods(env, "android/webkit/WebViewCore",
5087            gJavaWebViewCoreMethods, NELEM(gJavaWebViewCoreMethods));
5088}
5089
5090} /* namespace android */
5091