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