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