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