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