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