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