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