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