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