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