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