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