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