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