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