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