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