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