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