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