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