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