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