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