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