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