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