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