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