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