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