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