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