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