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