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