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