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