OSDN Git Service

Merge Chromium at r65505: Initiliase the OpenSSL library.
[android-x86/external-webkit.git] / WebKit / android / jni / WebViewCore.cpp
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 "BaseLayerAndroid.h"
33 #include "CachedNode.h"
34 #include "CachedRoot.h"
35 #include "Chrome.h"
36 #include "ChromeClientAndroid.h"
37 #include "ChromiumIncludes.h"
38 #include "Color.h"
39 #include "DatabaseTracker.h"
40 #include "Document.h"
41 #include "DOMWindow.h"
42 #include "DOMSelection.h"
43 #include "Element.h"
44 #include "Editor.h"
45 #include "EditorClientAndroid.h"
46 #include "EventHandler.h"
47 #include "EventNames.h"
48 #include "ExceptionCode.h"
49 #include "FocusController.h"
50 #include "Font.h"
51 #include "Frame.h"
52 #include "FrameLoader.h"
53 #include "FrameLoaderClientAndroid.h"
54 #include "FrameTree.h"
55 #include "FrameView.h"
56 #include "Geolocation.h"
57 #include "GraphicsContext.h"
58 #include "GraphicsJNI.h"
59 #include "HTMLAnchorElement.h"
60 #include "HTMLAreaElement.h"
61 #include "HTMLElement.h"
62 #include "HTMLFormControlElement.h"
63 #include "HTMLImageElement.h"
64 #include "HTMLInputElement.h"
65 #include "HTMLLabelElement.h"
66 #include "HTMLMapElement.h"
67 #include "HTMLNames.h"
68 #include "HTMLOptGroupElement.h"
69 #include "HTMLOptionElement.h"
70 #include "HTMLSelectElement.h"
71 #include "HTMLTextAreaElement.h"
72 #include "HistoryItem.h"
73 #include "HitTestRequest.h"
74 #include "HitTestResult.h"
75 #include "InlineTextBox.h"
76 #include "Navigator.h"
77 #include "Node.h"
78 #include "NodeList.h"
79 #include "Page.h"
80 #include "PageGroup.h"
81 #include "PlatformKeyboardEvent.h"
82 #include "PlatformString.h"
83 #include "PluginWidgetAndroid.h"
84 #include "PluginView.h"
85 #include "Position.h"
86 #include "ProgressTracker.h"
87 #include "Range.h"
88 #include "RenderBox.h"
89 #include "RenderInline.h"
90 #include "RenderLayer.h"
91 #include "RenderPart.h"
92 #include "RenderText.h"
93 #include "RenderTextControl.h"
94 #include "RenderThemeAndroid.h"
95 #include "RenderView.h"
96 #include "ResourceRequest.h"
97 #include "SchemeRegistry.h"
98 #include "SelectionController.h"
99 #include "Settings.h"
100 #include "SkANP.h"
101 #include "SkTemplates.h"
102 #include "SkTDArray.h"
103 #include "SkTypes.h"
104 #include "SkCanvas.h"
105 #include "SkPicture.h"
106 #include "SkUtils.h"
107 #include "Text.h"
108 #include "TypingCommand.h"
109 #include "WebCoreFrameBridge.h"
110 #include "WebFrameView.h"
111 #include "WindowsKeyboardCodes.h"
112 #include "android_graphics.h"
113 #include "autofill/WebAutoFill.h"
114 #include "markup.h"
115
116 #include <JNIHelp.h>
117 #include <JNIUtility.h>
118 #include <ui/KeycodeLabels.h>
119 #include <wtf/CurrentTime.h>
120 #include <wtf/text/AtomicString.h>
121 #include <wtf/text/StringImpl.h>
122
123 #if USE(V8)
124 #include "ScriptController.h"
125 #include "V8Counters.h"
126 #include <wtf/text/CString.h>
127 #endif
128
129 #if DEBUG_NAV_UI
130 #include "SkTime.h"
131 #endif
132
133 #if ENABLE(TOUCH_EVENTS) // Android
134 #include "PlatformTouchEvent.h"
135 #endif
136
137 #ifdef ANDROID_DOM_LOGGING
138 #include "AndroidLog.h"
139 #include "RenderTreeAsText.h"
140 #include <wtf/text/CString.h>
141
142 FILE* gDomTreeFile = 0;
143 FILE* gRenderTreeFile = 0;
144 #endif
145
146 #ifdef ANDROID_INSTRUMENT
147 #include "TimeCounter.h"
148 #endif
149
150 #if USE(ACCELERATED_COMPOSITING)
151 #include "GraphicsLayerAndroid.h"
152 #include "RenderLayerCompositor.h"
153 #endif
154
155 /*  We pass this flag when recording the actual content, so that we don't spend
156     time actually regionizing complex path clips, when all we really want to do
157     is record them.
158  */
159 #define PICT_RECORD_FLAGS   SkPicture::kUsePathBoundsForClip_RecordingFlag
160
161 ////////////////////////////////////////////////////////////////////////////////////////////////
162
163 namespace android {
164
165 static SkTDArray<WebViewCore*> gInstanceList;
166
167 void WebViewCore::addInstance(WebViewCore* inst) {
168     *gInstanceList.append() = inst;
169 }
170
171 void WebViewCore::removeInstance(WebViewCore* inst) {
172     int index = gInstanceList.find(inst);
173     LOG_ASSERT(index >= 0, "RemoveInstance inst not found");
174     if (index >= 0) {
175         gInstanceList.removeShuffle(index);
176     }
177 }
178
179 bool WebViewCore::isInstance(WebViewCore* inst) {
180     return gInstanceList.find(inst) >= 0;
181 }
182
183 jobject WebViewCore::getApplicationContext() {
184
185     // check to see if there is a valid webviewcore object
186     if (gInstanceList.isEmpty())
187         return 0;
188
189     // get the context from the webview
190     jobject context = gInstanceList[0]->getContext();
191
192     if (!context)
193         return 0;
194
195     // get the application context using JNI
196     JNIEnv* env = JSC::Bindings::getJNIEnv();
197     jclass contextClass = env->GetObjectClass(context);
198     jmethodID appContextMethod = env->GetMethodID(contextClass, "getApplicationContext", "()Landroid/content/Context;");
199     env->DeleteLocalRef(contextClass);
200     jobject result = env->CallObjectMethod(context, appContextMethod);
201     checkException(env);
202     return result;
203 }
204
205
206 struct WebViewCoreStaticMethods {
207     jmethodID    m_isSupportedMediaMimeType;
208 } gWebViewCoreStaticMethods;
209
210 // Check whether a media mimeType is supported in Android media framework.
211 bool WebViewCore::isSupportedMediaMimeType(const WTF::String& mimeType) {
212     JNIEnv* env = JSC::Bindings::getJNIEnv();
213     jstring jMimeType = WtfStringToJstring(env, mimeType);
214     jclass webViewCore = env->FindClass("android/webkit/WebViewCore");
215     bool val = env->CallStaticBooleanMethod(webViewCore,
216           gWebViewCoreStaticMethods.m_isSupportedMediaMimeType, jMimeType);
217     checkException(env);
218     env->DeleteLocalRef(webViewCore);
219     env->DeleteLocalRef(jMimeType);
220
221     return val;
222 }
223
224 // ----------------------------------------------------------------------------
225
226 #define GET_NATIVE_VIEW(env, obj) ((WebViewCore*)env->GetIntField(obj, gWebViewCoreFields.m_nativeClass))
227
228 // Field ids for WebViewCore
229 struct WebViewCoreFields {
230     jfieldID    m_nativeClass;
231     jfieldID    m_viewportWidth;
232     jfieldID    m_viewportHeight;
233     jfieldID    m_viewportInitialScale;
234     jfieldID    m_viewportMinimumScale;
235     jfieldID    m_viewportMaximumScale;
236     jfieldID    m_viewportUserScalable;
237     jfieldID    m_viewportDensityDpi;
238     jfieldID    m_webView;
239     jfieldID    m_drawIsPaused;
240 } gWebViewCoreFields;
241
242 // ----------------------------------------------------------------------------
243
244 struct WebViewCore::JavaGlue {
245     jweak       m_obj;
246     jmethodID   m_spawnScrollTo;
247     jmethodID   m_scrollTo;
248     jmethodID   m_scrollBy;
249     jmethodID   m_contentDraw;
250     jmethodID   m_layersDraw;
251     jmethodID   m_requestListBox;
252     jmethodID   m_openFileChooser;
253     jmethodID   m_requestSingleListBox;
254     jmethodID   m_jsAlert;
255     jmethodID   m_jsConfirm;
256     jmethodID   m_jsPrompt;
257     jmethodID   m_jsUnload;
258     jmethodID   m_jsInterrupt;
259     jmethodID   m_didFirstLayout;
260     jmethodID   m_updateViewport;
261     jmethodID   m_sendNotifyProgressFinished;
262     jmethodID   m_sendViewInvalidate;
263     jmethodID   m_updateTextfield;
264     jmethodID   m_updateTextSelection;
265     jmethodID   m_clearTextEntry;
266     jmethodID   m_restoreScale;
267     jmethodID   m_needTouchEvents;
268     jmethodID   m_requestKeyboard;
269     jmethodID   m_requestKeyboardWithSelection;
270     jmethodID   m_exceededDatabaseQuota;
271     jmethodID   m_reachedMaxAppCacheSize;
272     jmethodID   m_populateVisitedLinks;
273     jmethodID   m_geolocationPermissionsShowPrompt;
274     jmethodID   m_geolocationPermissionsHidePrompt;
275     jmethodID   m_getDeviceMotionService;
276     jmethodID   m_getDeviceOrientationService;
277     jmethodID   m_addMessageToConsole;
278     jmethodID   m_formDidBlur;
279     jmethodID   m_getPluginClass;
280     jmethodID   m_showFullScreenPlugin;
281     jmethodID   m_hideFullScreenPlugin;
282     jmethodID   m_addSurface;
283     jmethodID   m_updateSurface;
284     jmethodID   m_destroySurface;
285     jmethodID   m_getContext;
286     jmethodID   m_sendFindAgain;
287     jmethodID   m_showRect;
288     jmethodID   m_centerFitRect;
289     jmethodID   m_setScrollbarModes;
290     jmethodID   m_setInstallableWebApp;
291     jmethodID   m_setWebTextViewAutoFillable;
292     AutoJObject object(JNIEnv* env) {
293         return getRealObject(env, m_obj);
294     }
295 };
296
297 /*
298  * WebViewCore Implementation
299  */
300
301 static jmethodID GetJMethod(JNIEnv* env, jclass clazz, const char name[], const char signature[])
302 {
303     jmethodID m = env->GetMethodID(clazz, name, signature);
304     LOG_ASSERT(m, "Could not find method %s", name);
305     return m;
306 }
307
308 Mutex WebViewCore::gFrameCacheMutex;
309 Mutex WebViewCore::gButtonMutex;
310 Mutex WebViewCore::gCursorBoundsMutex;
311
312 WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* mainframe)
313     : m_pluginInvalTimer(this, &WebViewCore::pluginInvalTimerFired)
314     , m_deviceMotionAndOrientationManager(this)
315 {
316     m_mainFrame = mainframe;
317
318     m_popupReply = 0;
319     m_moveGeneration = 0;
320     m_lastGeneration = 0;
321     m_touchGeneration = 0;
322     m_blockTextfieldUpdates = false;
323     // just initial values. These should be set by client
324     m_maxXScroll = 320/4;
325     m_maxYScroll = 240/4;
326     m_textGeneration = 0;
327     m_screenWidth = 320;
328     m_textWrapWidth = 320;
329     m_scale = 1;
330 #if ENABLE(TOUCH_EVENTS)
331     m_forwardingTouchEvents = false;
332 #endif
333     m_isPaused = false;
334
335     LOG_ASSERT(m_mainFrame, "Uh oh, somehow a frameview was made without an initial frame!");
336
337     jclass clazz = env->GetObjectClass(javaWebViewCore);
338     m_javaGlue = new JavaGlue;
339     m_javaGlue->m_obj = env->NewWeakGlobalRef(javaWebViewCore);
340     m_javaGlue->m_spawnScrollTo = GetJMethod(env, clazz, "contentSpawnScrollTo", "(II)V");
341     m_javaGlue->m_scrollTo = GetJMethod(env, clazz, "contentScrollTo", "(II)V");
342     m_javaGlue->m_scrollBy = GetJMethod(env, clazz, "contentScrollBy", "(IIZ)V");
343     m_javaGlue->m_contentDraw = GetJMethod(env, clazz, "contentDraw", "()V");
344     m_javaGlue->m_layersDraw = GetJMethod(env, clazz, "layersDraw", "()V");
345     m_javaGlue->m_requestListBox = GetJMethod(env, clazz, "requestListBox", "([Ljava/lang/String;[I[I)V");
346     m_javaGlue->m_openFileChooser = GetJMethod(env, clazz, "openFileChooser", "(Ljava/lang/String;)Ljava/lang/String;");
347     m_javaGlue->m_requestSingleListBox = GetJMethod(env, clazz, "requestListBox", "([Ljava/lang/String;[II)V");
348     m_javaGlue->m_jsAlert = GetJMethod(env, clazz, "jsAlert", "(Ljava/lang/String;Ljava/lang/String;)V");
349     m_javaGlue->m_jsConfirm = GetJMethod(env, clazz, "jsConfirm", "(Ljava/lang/String;Ljava/lang/String;)Z");
350     m_javaGlue->m_jsPrompt = GetJMethod(env, clazz, "jsPrompt", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
351     m_javaGlue->m_jsUnload = GetJMethod(env, clazz, "jsUnload", "(Ljava/lang/String;Ljava/lang/String;)Z");
352     m_javaGlue->m_jsInterrupt = GetJMethod(env, clazz, "jsInterrupt", "()Z");
353     m_javaGlue->m_didFirstLayout = GetJMethod(env, clazz, "didFirstLayout", "(Z)V");
354     m_javaGlue->m_updateViewport = GetJMethod(env, clazz, "updateViewport", "()V");
355     m_javaGlue->m_sendNotifyProgressFinished = GetJMethod(env, clazz, "sendNotifyProgressFinished", "()V");
356     m_javaGlue->m_sendViewInvalidate = GetJMethod(env, clazz, "sendViewInvalidate", "(IIII)V");
357     m_javaGlue->m_updateTextfield = GetJMethod(env, clazz, "updateTextfield", "(IZLjava/lang/String;I)V");
358     m_javaGlue->m_updateTextSelection = GetJMethod(env, clazz, "updateTextSelection", "(IIII)V");
359     m_javaGlue->m_clearTextEntry = GetJMethod(env, clazz, "clearTextEntry", "()V");
360     m_javaGlue->m_restoreScale = GetJMethod(env, clazz, "restoreScale", "(II)V");
361     m_javaGlue->m_needTouchEvents = GetJMethod(env, clazz, "needTouchEvents", "(Z)V");
362     m_javaGlue->m_requestKeyboard = GetJMethod(env, clazz, "requestKeyboard", "(Z)V");
363     m_javaGlue->m_requestKeyboardWithSelection = GetJMethod(env, clazz, "requestKeyboardWithSelection", "(IIII)V");
364     m_javaGlue->m_exceededDatabaseQuota = GetJMethod(env, clazz, "exceededDatabaseQuota", "(Ljava/lang/String;Ljava/lang/String;JJ)V");
365     m_javaGlue->m_reachedMaxAppCacheSize = GetJMethod(env, clazz, "reachedMaxAppCacheSize", "(J)V");
366     m_javaGlue->m_populateVisitedLinks = GetJMethod(env, clazz, "populateVisitedLinks", "()V");
367     m_javaGlue->m_geolocationPermissionsShowPrompt = GetJMethod(env, clazz, "geolocationPermissionsShowPrompt", "(Ljava/lang/String;)V");
368     m_javaGlue->m_geolocationPermissionsHidePrompt = GetJMethod(env, clazz, "geolocationPermissionsHidePrompt", "()V");
369     m_javaGlue->m_getDeviceMotionService = GetJMethod(env, clazz, "getDeviceMotionService", "()Landroid/webkit/DeviceMotionService;");
370     m_javaGlue->m_getDeviceOrientationService = GetJMethod(env, clazz, "getDeviceOrientationService", "()Landroid/webkit/DeviceOrientationService;");
371     m_javaGlue->m_addMessageToConsole = GetJMethod(env, clazz, "addMessageToConsole", "(Ljava/lang/String;ILjava/lang/String;I)V");
372     m_javaGlue->m_formDidBlur = GetJMethod(env, clazz, "formDidBlur", "(I)V");
373     m_javaGlue->m_getPluginClass = GetJMethod(env, clazz, "getPluginClass", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Class;");
374     m_javaGlue->m_showFullScreenPlugin = GetJMethod(env, clazz, "showFullScreenPlugin", "(Landroid/webkit/ViewManager$ChildView;I)V");
375     m_javaGlue->m_hideFullScreenPlugin = GetJMethod(env, clazz, "hideFullScreenPlugin", "()V");
376     m_javaGlue->m_addSurface = GetJMethod(env, clazz, "addSurface", "(Landroid/view/View;IIII)Landroid/webkit/ViewManager$ChildView;");
377     m_javaGlue->m_updateSurface = GetJMethod(env, clazz, "updateSurface", "(Landroid/webkit/ViewManager$ChildView;IIII)V");
378     m_javaGlue->m_destroySurface = GetJMethod(env, clazz, "destroySurface", "(Landroid/webkit/ViewManager$ChildView;)V");
379     m_javaGlue->m_getContext = GetJMethod(env, clazz, "getContext", "()Landroid/content/Context;");
380     m_javaGlue->m_sendFindAgain = GetJMethod(env, clazz, "sendFindAgain", "()V");
381     m_javaGlue->m_showRect = GetJMethod(env, clazz, "showRect", "(IIIIIIFFFF)V");
382     m_javaGlue->m_centerFitRect = GetJMethod(env, clazz, "centerFitRect", "(IIII)V");
383     m_javaGlue->m_setScrollbarModes = GetJMethod(env, clazz, "setScrollbarModes", "(II)V");
384     m_javaGlue->m_setInstallableWebApp = GetJMethod(env, clazz, "setInstallableWebApp", "()V");
385     m_javaGlue->m_setWebTextViewAutoFillable = GetJMethod(env, clazz, "setWebTextViewAutoFillable", "(ILjava/lang/String;)V");
386     env->DeleteLocalRef(clazz);
387
388     env->SetIntField(javaWebViewCore, gWebViewCoreFields.m_nativeClass, (jint)this);
389
390     m_scrollOffsetX = m_scrollOffsetY = 0;
391
392     PageGroup::setShouldTrackVisitedLinks(true);
393
394     reset(true);
395
396     WebViewCore::addInstance(this);
397
398 #if USE(CHROME_NETWORK_STACK)
399     AndroidNetworkLibraryImpl::InitWithApplicationContext(env, 0);
400 #endif
401 }
402
403 WebViewCore::~WebViewCore()
404 {
405     WebViewCore::removeInstance(this);
406
407     // Release the focused view
408     Release(m_popupReply);
409
410     if (m_javaGlue->m_obj) {
411         JNIEnv* env = JSC::Bindings::getJNIEnv();
412         env->DeleteWeakGlobalRef(m_javaGlue->m_obj);
413         m_javaGlue->m_obj = 0;
414     }
415     delete m_javaGlue;
416     delete m_frameCacheKit;
417     delete m_navPictureKit;
418 }
419
420 WebViewCore* WebViewCore::getWebViewCore(const WebCore::FrameView* view)
421 {
422     return getWebViewCore(static_cast<const WebCore::ScrollView*>(view));
423 }
424
425 WebViewCore* WebViewCore::getWebViewCore(const WebCore::ScrollView* view)
426 {
427     if (!view)
428         return 0;
429
430     WebFrameView* webFrameView = static_cast<WebFrameView*>(view->platformWidget());
431     if (!webFrameView)
432         return 0;
433     return webFrameView->webViewCore();
434 }
435
436 void WebViewCore::reset(bool fromConstructor)
437 {
438     DBG_SET_LOG("");
439     if (fromConstructor) {
440         m_frameCacheKit = 0;
441         m_navPictureKit = 0;
442     } else {
443         gFrameCacheMutex.lock();
444         delete m_frameCacheKit;
445         delete m_navPictureKit;
446         m_frameCacheKit = 0;
447         m_navPictureKit = 0;
448         gFrameCacheMutex.unlock();
449     }
450
451     m_lastFocused = 0;
452     m_lastFocusedBounds = WebCore::IntRect(0,0,0,0);
453     m_focusBoundsChanged = false;
454     m_lastFocusedSelStart = 0;
455     m_lastFocusedSelEnd = 0;
456     clearContent();
457     m_updatedFrameCache = true;
458     m_frameCacheOutOfDate = true;
459     m_skipContentDraw = false;
460     m_findIsUp = false;
461     m_domtree_version = 0;
462     m_check_domtree_version = true;
463     m_progressDone = false;
464     m_hasCursorBounds = false;
465
466     m_scrollOffsetX = 0;
467     m_scrollOffsetY = 0;
468     m_screenWidth = 0;
469     m_screenHeight = 0;
470     m_groupForVisitedLinks = NULL;
471     m_currentNodeDomNavigationAxis = 0;
472 }
473
474 static bool layoutIfNeededRecursive(WebCore::Frame* f)
475 {
476     if (!f)
477         return true;
478
479     WebCore::FrameView* v = f->view();
480     if (!v)
481         return true;
482
483     if (v->needsLayout())
484         v->layout(f->tree()->parent());
485
486     WebCore::Frame* child = f->tree()->firstChild();
487     bool success = true;
488     while (child) {
489         success &= layoutIfNeededRecursive(child);
490         child = child->tree()->nextSibling();
491     }
492
493     return success && !v->needsLayout();
494 }
495
496 CacheBuilder& WebViewCore::cacheBuilder()
497 {
498     return FrameLoaderClientAndroid::get(m_mainFrame)->getCacheBuilder();
499 }
500
501 WebCore::Node* WebViewCore::currentFocus()
502 {
503     return cacheBuilder().currentFocus();
504 }
505
506 void WebViewCore::recordPicture(SkPicture* picture)
507 {
508     // if there is no document yet, just return
509     if (!m_mainFrame->document()) {
510         DBG_NAV_LOG("no document");
511         return;
512     }
513     // Call layout to ensure that the contentWidth and contentHeight are correct
514     if (!layoutIfNeededRecursive(m_mainFrame)) {
515         DBG_NAV_LOG("layout failed");
516         return;
517     }
518     // draw into the picture's recording canvas
519     WebCore::FrameView* view = m_mainFrame->view();
520     DBG_NAV_LOGD("view=(w=%d,h=%d)", view->contentsWidth(),
521         view->contentsHeight());
522     SkAutoPictureRecord arp(picture, view->contentsWidth(),
523                             view->contentsHeight(), PICT_RECORD_FLAGS);
524     SkAutoMemoryUsageProbe mup(__FUNCTION__);
525
526     // Copy m_buttons so we can pass it to our graphics context.
527     gButtonMutex.lock();
528     WTF::Vector<Container> buttons(m_buttons);
529     gButtonMutex.unlock();
530
531     WebCore::PlatformGraphicsContext pgc(arp.getRecordingCanvas(), &buttons);
532     WebCore::GraphicsContext gc(&pgc);
533     view->platformWidget()->draw(&gc, WebCore::IntRect(0, 0,
534         view->contentsWidth(), view->contentsHeight()));
535
536     gButtonMutex.lock();
537     updateButtonList(&buttons);
538     gButtonMutex.unlock();
539 }
540
541 void WebViewCore::recordPictureSet(PictureSet* content)
542 {
543     // if there is no document yet, just return
544     if (!m_mainFrame->document()) {
545         DBG_SET_LOG("!m_mainFrame->document()");
546         return;
547     }
548     if (m_addInval.isEmpty()) {
549         DBG_SET_LOG("m_addInval.isEmpty()");
550         return;
551     }
552     // Call layout to ensure that the contentWidth and contentHeight are correct
553     // it's fine for layout to gather invalidates, but defeat sending a message
554     // back to java to call webkitDraw, since we're already in the middle of
555     // doing that
556     m_skipContentDraw = true;
557     bool success = layoutIfNeededRecursive(m_mainFrame);
558     m_skipContentDraw = false;
559
560     // We may be mid-layout and thus cannot draw.
561     if (!success)
562         return;
563
564     {   // collect WebViewCoreRecordTimeCounter after layoutIfNeededRecursive
565 #ifdef ANDROID_INSTRUMENT
566     TimeCounterAuto counter(TimeCounter::WebViewCoreRecordTimeCounter);
567 #endif
568
569     // if the webkit page dimensions changed, discard the pictureset and redraw.
570     WebCore::FrameView* view = m_mainFrame->view();
571     int width = view->contentsWidth();
572     int height = view->contentsHeight();
573
574     // Use the contents width and height as a starting point.
575     SkIRect contentRect;
576     contentRect.set(0, 0, width, height);
577     SkIRect total(contentRect);
578
579     // Traverse all the frames and add their sizes if they are in the visible
580     // rectangle.
581     for (WebCore::Frame* frame = m_mainFrame->tree()->traverseNext(); frame;
582             frame = frame->tree()->traverseNext()) {
583         // If the frame doesn't have an owner then it is the top frame and the
584         // view size is the frame size.
585         WebCore::RenderPart* owner = frame->ownerRenderer();
586         if (owner && owner->style()->visibility() == VISIBLE) {
587             int x = owner->x();
588             int y = owner->y();
589
590             // Traverse the tree up to the parent to find the absolute position
591             // of this frame.
592             WebCore::Frame* parent = frame->tree()->parent();
593             while (parent) {
594                 WebCore::RenderPart* parentOwner = parent->ownerRenderer();
595                 if (parentOwner) {
596                     x += parentOwner->x();
597                     y += parentOwner->y();
598                 }
599                 parent = parent->tree()->parent();
600             }
601             // Use the owner dimensions so that padding and border are
602             // included.
603             int right = x + owner->width();
604             int bottom = y + owner->height();
605             SkIRect frameRect = {x, y, right, bottom};
606             // Ignore a width or height that is smaller than 1. Some iframes
607             // have small dimensions in order to be hidden. The iframe
608             // expansion code does not expand in that case so we should ignore
609             // them here.
610             if (frameRect.width() > 1 && frameRect.height() > 1
611                     && SkIRect::Intersects(total, frameRect))
612                 total.join(x, y, right, bottom);
613         }
614     }
615
616     // If the new total is larger than the content, resize the view to include
617     // all the content.
618     if (!contentRect.contains(total)) {
619         // Resize the view to change the overflow clip.
620         view->resize(total.fRight, total.fBottom);
621
622         // We have to force a layout in order for the clip to change.
623         m_mainFrame->contentRenderer()->setNeedsLayoutAndPrefWidthsRecalc();
624         view->forceLayout();
625
626         // Relayout similar to above
627         m_skipContentDraw = true;
628         bool success = layoutIfNeededRecursive(m_mainFrame);
629         m_skipContentDraw = false;
630         if (!success)
631             return;
632
633         // Set the computed content width
634         width = view->contentsWidth();
635         height = view->contentsHeight();
636     }
637
638     if (cacheBuilder().pictureSetDisabled())
639         content->clear();
640
641     content->checkDimensions(width, height, &m_addInval);
642
643     // The inval region may replace existing pictures. The existing pictures
644     // may have already been split into pieces. If reuseSubdivided() returns
645     // true, the split pieces are the last entries in the picture already. They
646     // are marked as invalid, and are rebuilt by rebuildPictureSet().
647
648     // If the new region doesn't match a set of split pieces, add it to the end.
649     if (!content->reuseSubdivided(m_addInval)) {
650         const SkIRect& inval = m_addInval.getBounds();
651         SkPicture* picture = rebuildPicture(inval);
652         DBG_SET_LOGD("{%d,%d,w=%d,h=%d}", inval.fLeft,
653             inval.fTop, inval.width(), inval.height());
654         content->add(m_addInval, picture, 0, false);
655         picture->safeUnref();
656     }
657     // Remove any pictures already in the set that are obscured by the new one,
658     // and check to see if any already split pieces need to be redrawn.
659     if (content->build())
660         rebuildPictureSet(content);
661     } // WebViewCoreRecordTimeCounter
662     WebCore::Node* oldFocusNode = currentFocus();
663     m_frameCacheOutOfDate = true;
664     WebCore::IntRect oldBounds;
665     int oldSelStart = 0;
666     int oldSelEnd = 0;
667     if (oldFocusNode) {
668         oldBounds = oldFocusNode->getRect();
669         RenderObject* renderer = oldFocusNode->renderer();
670         if (renderer && (renderer->isTextArea() || renderer->isTextField())) {
671             WebCore::RenderTextControl* rtc =
672                 static_cast<WebCore::RenderTextControl*>(renderer);
673             oldSelStart = rtc->selectionStart();
674             oldSelEnd = rtc->selectionEnd();
675         }
676     } else
677         oldBounds = WebCore::IntRect(0,0,0,0);
678     unsigned latestVersion = 0;
679     if (m_check_domtree_version) {
680         // as domTreeVersion only increment, we can just check the sum to see
681         // whether we need to update the frame cache
682         for (Frame* frame = m_mainFrame; frame; frame = frame->tree()->traverseNext()) {
683             const Document* doc = frame->document();
684             latestVersion += doc->domTreeVersion() + doc->styleVersion();
685         }
686     }
687     DBG_NAV_LOGD("m_lastFocused=%p oldFocusNode=%p"
688         " m_lastFocusedBounds={%d,%d,%d,%d} oldBounds={%d,%d,%d,%d}"
689         " m_lastFocusedSelection={%d,%d} oldSelection={%d,%d}"
690         " m_check_domtree_version=%s latestVersion=%d m_domtree_version=%d",
691         m_lastFocused, oldFocusNode,
692         m_lastFocusedBounds.x(), m_lastFocusedBounds.y(),
693         m_lastFocusedBounds.width(), m_lastFocusedBounds.height(),
694         oldBounds.x(), oldBounds.y(), oldBounds.width(), oldBounds.height(),
695         m_lastFocusedSelStart, m_lastFocusedSelEnd, oldSelStart, oldSelEnd,
696         m_check_domtree_version ? "true" : "false",
697         latestVersion, m_domtree_version);
698     if (m_lastFocused == oldFocusNode && m_lastFocusedBounds == oldBounds
699             && m_lastFocusedSelStart == oldSelStart
700             && m_lastFocusedSelEnd == oldSelEnd
701             && !m_findIsUp
702             && (!m_check_domtree_version || latestVersion == m_domtree_version))
703     {
704         return;
705     }
706     m_focusBoundsChanged |= m_lastFocused == oldFocusNode
707         && m_lastFocusedBounds != oldBounds;
708     m_lastFocused = oldFocusNode;
709     m_lastFocusedBounds = oldBounds;
710     m_lastFocusedSelStart = oldSelStart;
711     m_lastFocusedSelEnd = oldSelEnd;
712     m_domtree_version = latestVersion;
713     DBG_NAV_LOG("call updateFrameCache");
714     updateFrameCache();
715     if (m_findIsUp) {
716         LOG_ASSERT(m_javaGlue->m_obj,
717                 "A Java widget was not associated with this view bridge!");
718         JNIEnv* env = JSC::Bindings::getJNIEnv();
719         env->CallVoidMethod(m_javaGlue->object(env).get(),
720                 m_javaGlue->m_sendFindAgain);
721         checkException(env);
722     }
723 }
724
725 void WebViewCore::updateButtonList(WTF::Vector<Container>* buttons)
726 {
727     // All the entries in buttons are either updates of previous entries in
728     // m_buttons or they need to be added to it.
729     Container* end = buttons->end();
730     for (Container* updatedContainer = buttons->begin();
731             updatedContainer != end; updatedContainer++) {
732         bool updated = false;
733         // Search for a previous entry that references the same node as our new
734         // data
735         Container* lastPossibleMatch = m_buttons.end();
736         for (Container* possibleMatch = m_buttons.begin();
737                 possibleMatch != lastPossibleMatch; possibleMatch++) {
738             if (updatedContainer->matches(possibleMatch->node())) {
739                 // Update our record, and skip to the next one.
740                 possibleMatch->setRect(updatedContainer->rect());
741                 updated = true;
742                 break;
743             }
744         }
745         if (!updated) {
746             // This is a brand new button, so append it to m_buttons
747             m_buttons.append(*updatedContainer);
748         }
749     }
750     size_t i = 0;
751     // count will decrease each time one is removed, so check count each time.
752     while (i < m_buttons.size()) {
753         if (m_buttons[i].canBeRemoved()) {
754             m_buttons[i] = m_buttons.last();
755             m_buttons.removeLast();
756         } else {
757             i++;
758         }
759     }
760 }
761
762 // note: updateCursorBounds is called directly by the WebView thread
763 // This needs to be called each time we call CachedRoot::setCursor() with
764 // non-null CachedNode/CachedFrame, since otherwise the WebViewCore's data
765 // about the cursor is incorrect.  When we call setCursor(0,0), we need
766 // to set hasCursorBounds to false.
767 void WebViewCore::updateCursorBounds(const CachedRoot* root,
768         const CachedFrame* cachedFrame, const CachedNode* cachedNode)
769 {
770     LOG_ASSERT(root, "updateCursorBounds: root cannot be null");
771     LOG_ASSERT(cachedNode, "updateCursorBounds: cachedNode cannot be null");
772     LOG_ASSERT(cachedFrame, "updateCursorBounds: cachedFrame cannot be null");
773     gCursorBoundsMutex.lock();
774     m_hasCursorBounds = !cachedNode->isHidden();
775     // If m_hasCursorBounds is false, we never look at the other
776     // values, so do not bother setting them.
777     if (m_hasCursorBounds) {
778         WebCore::IntRect bounds = cachedNode->bounds(cachedFrame);
779         if (m_cursorBounds != bounds)
780             DBG_NAV_LOGD("new cursor bounds=(%d,%d,w=%d,h=%d)",
781                 bounds.x(), bounds.y(), bounds.width(), bounds.height());
782         m_cursorBounds = bounds;
783         m_cursorHitBounds = cachedNode->hitBounds(cachedFrame);
784         m_cursorFrame = cachedFrame->framePointer();
785         root->getSimulatedMousePosition(&m_cursorLocation);
786         m_cursorNode = cachedNode->nodePointer();
787     }
788     gCursorBoundsMutex.unlock();
789 }
790
791 void WebViewCore::clearContent()
792 {
793     DBG_SET_LOG("");
794     m_content.clear();
795     m_addInval.setEmpty();
796     m_rebuildInval.setEmpty();
797 }
798
799 bool WebViewCore::focusBoundsChanged()
800 {
801     bool result = m_focusBoundsChanged;
802     m_focusBoundsChanged = false;
803     return result;
804 }
805
806 SkPicture* WebViewCore::rebuildPicture(const SkIRect& inval)
807 {
808     WebCore::FrameView* view = m_mainFrame->view();
809     int width = view->contentsWidth();
810     int height = view->contentsHeight();
811     SkPicture* picture = new SkPicture();
812     SkAutoPictureRecord arp(picture, width, height, PICT_RECORD_FLAGS);
813     SkAutoMemoryUsageProbe mup(__FUNCTION__);
814     SkCanvas* recordingCanvas = arp.getRecordingCanvas();
815
816     gButtonMutex.lock();
817     WTF::Vector<Container> buttons(m_buttons);
818     gButtonMutex.unlock();
819
820     WebCore::PlatformGraphicsContext pgc(recordingCanvas, &buttons);
821     WebCore::GraphicsContext gc(&pgc);
822     recordingCanvas->translate(-inval.fLeft, -inval.fTop);
823     recordingCanvas->save();
824     view->platformWidget()->draw(&gc, WebCore::IntRect(inval.fLeft,
825         inval.fTop, inval.width(), inval.height()));
826     m_rebuildInval.op(inval, SkRegion::kUnion_Op);
827     DBG_SET_LOGD("m_rebuildInval={%d,%d,r=%d,b=%d}",
828         m_rebuildInval.getBounds().fLeft, m_rebuildInval.getBounds().fTop,
829         m_rebuildInval.getBounds().fRight, m_rebuildInval.getBounds().fBottom);
830
831     gButtonMutex.lock();
832     updateButtonList(&buttons);
833     gButtonMutex.unlock();
834
835     return picture;
836 }
837
838 void WebViewCore::rebuildPictureSet(PictureSet* pictureSet)
839 {
840     WebCore::FrameView* view = m_mainFrame->view();
841     size_t size = pictureSet->size();
842     for (size_t index = 0; index < size; index++) {
843         if (pictureSet->upToDate(index))
844             continue;
845         const SkIRect& inval = pictureSet->bounds(index);
846         DBG_SET_LOGD("pictSet=%p [%d] {%d,%d,w=%d,h=%d}", pictureSet, index,
847             inval.fLeft, inval.fTop, inval.width(), inval.height());
848         pictureSet->setPicture(index, rebuildPicture(inval));
849     }
850     pictureSet->validate(__FUNCTION__);
851 }
852
853 BaseLayerAndroid* WebViewCore::createBaseLayer()
854 {
855     BaseLayerAndroid* base = new BaseLayerAndroid();
856     base->setContent(m_content);
857
858 #if USE(ACCELERATED_COMPOSITING)
859     // We set the background color
860     if (m_mainFrame && m_mainFrame->document()
861         && m_mainFrame->document()->body()) {
862         Document* document = m_mainFrame->document();
863         RefPtr<RenderStyle> style = document->styleForElementIgnoringPendingStylesheets(document->body());
864         if (style->hasBackground()) {
865             Color color = style->visitedDependentColor(CSSPropertyBackgroundColor);
866             base->setBackgroundColor(color);
867         }
868     }
869
870     // We update the layers
871     ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(m_mainFrame->page()->chrome()->client());
872     GraphicsLayerAndroid* root = static_cast<GraphicsLayerAndroid*>(chromeC->layersSync());
873     if (root) {
874         root->notifyClientAnimationStarted();
875         LayerAndroid* copyLayer = new LayerAndroid(*root->contentLayer());
876         base->addChild(copyLayer);
877         copyLayer->unref();
878     }
879 #endif
880
881     return base;
882 }
883
884 BaseLayerAndroid* WebViewCore::recordContent(SkRegion* region, SkIPoint* point)
885 {
886     DBG_SET_LOG("start");
887     float progress = (float) m_mainFrame->page()->progress()->estimatedProgress();
888     m_progressDone = progress <= 0.0f || progress >= 1.0f;
889     recordPictureSet(&m_content);
890     if (!m_progressDone && m_content.isEmpty()) {
891         DBG_SET_LOGD("empty (progress=%g)", progress);
892         return 0;
893     }
894     region->set(m_addInval);
895     m_addInval.setEmpty();
896     region->op(m_rebuildInval, SkRegion::kUnion_Op);
897     m_rebuildInval.setEmpty();
898     point->fX = m_content.width();
899     point->fY = m_content.height();
900     DBG_SET_LOGD("region={%d,%d,r=%d,b=%d}", region->getBounds().fLeft,
901         region->getBounds().fTop, region->getBounds().fRight,
902         region->getBounds().fBottom);
903     DBG_SET_LOG("end");
904
905     return createBaseLayer();
906 }
907
908 void WebViewCore::splitContent(PictureSet* content)
909 {
910     bool layoutSuceeded = layoutIfNeededRecursive(m_mainFrame);
911     LOG_ASSERT(layoutSuceeded, "Can never be called recursively");
912     content->split(&m_content);
913     rebuildPictureSet(&m_content);
914     content->set(m_content);
915 }
916
917 void WebViewCore::scrollTo(int x, int y, bool animate)
918 {
919     LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
920
921 //    LOGD("WebViewCore::scrollTo(%d %d)\n", x, y);
922
923     JNIEnv* env = JSC::Bindings::getJNIEnv();
924     env->CallVoidMethod(m_javaGlue->object(env).get(),
925             animate ? m_javaGlue->m_spawnScrollTo : m_javaGlue->m_scrollTo,
926             x, y);
927     checkException(env);
928 }
929
930 void WebViewCore::sendNotifyProgressFinished()
931 {
932     LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
933     JNIEnv* env = JSC::Bindings::getJNIEnv();
934     env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_sendNotifyProgressFinished);
935     checkException(env);
936 }
937
938 void WebViewCore::viewInvalidate(const WebCore::IntRect& rect)
939 {
940     LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
941     JNIEnv* env = JSC::Bindings::getJNIEnv();
942     env->CallVoidMethod(m_javaGlue->object(env).get(),
943                         m_javaGlue->m_sendViewInvalidate,
944                         rect.x(), rect.y(), rect.right(), rect.bottom());
945     checkException(env);
946 }
947
948 void WebViewCore::scrollBy(int dx, int dy, bool animate)
949 {
950     if (!(dx | dy))
951         return;
952     JNIEnv* env = JSC::Bindings::getJNIEnv();
953     env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_scrollBy,
954         dx, dy, animate);
955     checkException(env);
956 }
957
958 void WebViewCore::contentDraw()
959 {
960     JNIEnv* env = JSC::Bindings::getJNIEnv();
961     env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_contentDraw);
962     checkException(env);
963 }
964
965 void WebViewCore::layersDraw()
966 {
967     JNIEnv* env = JSC::Bindings::getJNIEnv();
968     env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_layersDraw);
969     checkException(env);
970 }
971
972 void WebViewCore::contentInvalidate(const WebCore::IntRect &r)
973 {
974     DBG_SET_LOGD("rect={%d,%d,w=%d,h=%d}", r.x(), r.y(), r.width(), r.height());
975     SkIRect rect(r);
976     if (!rect.intersect(0, 0, INT_MAX, INT_MAX))
977         return;
978     m_addInval.op(rect, SkRegion::kUnion_Op);
979     DBG_SET_LOGD("m_addInval={%d,%d,r=%d,b=%d}",
980         m_addInval.getBounds().fLeft, m_addInval.getBounds().fTop,
981         m_addInval.getBounds().fRight, m_addInval.getBounds().fBottom);
982     if (!m_skipContentDraw)
983         contentDraw();
984 }
985
986 void WebViewCore::contentInvalidateAll()
987 {
988     WebCore::FrameView* view = m_mainFrame->view();
989     contentInvalidate(WebCore::IntRect(0, 0,
990         view->contentsWidth(), view->contentsHeight()));
991 }
992
993 void WebViewCore::offInvalidate(const WebCore::IntRect &r)
994 {
995     // FIXME: these invalidates are offscreen, and can be throttled or
996     // deferred until the area is visible. For now, treat them as
997     // regular invals so that drawing happens (inefficiently) for now.
998     contentInvalidate(r);
999 }
1000
1001 static int pin_pos(int x, int width, int targetWidth)
1002 {
1003     if (x + width > targetWidth)
1004         x = targetWidth - width;
1005     if (x < 0)
1006         x = 0;
1007     return x;
1008 }
1009
1010 void WebViewCore::didFirstLayout()
1011 {
1012     DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
1013     LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
1014
1015     WebCore::FrameLoader* loader = m_mainFrame->loader();
1016     const WebCore::KURL& url = loader->url();
1017     if (url.isEmpty())
1018         return;
1019     LOGV("::WebCore:: didFirstLayout %s", url.string().ascii().data());
1020
1021     WebCore::FrameLoadType loadType = loader->loadType();
1022
1023     JNIEnv* env = JSC::Bindings::getJNIEnv();
1024     env->CallVoidMethod(m_javaGlue->object(env).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     checkException(env);
1031
1032     DBG_NAV_LOG("call updateFrameCache");
1033     m_check_domtree_version = false;
1034     updateFrameCache();
1035     m_history.setDidFirstLayout(true);
1036 }
1037
1038 void WebViewCore::updateViewport()
1039 {
1040     DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
1041     LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
1042
1043     JNIEnv* env = JSC::Bindings::getJNIEnv();
1044     env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_updateViewport);
1045     checkException(env);
1046 }
1047
1048 void WebViewCore::restoreScale(int scale, int textWrapScale)
1049 {
1050     DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
1051     LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
1052
1053     JNIEnv* env = JSC::Bindings::getJNIEnv();
1054     env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_restoreScale, scale, textWrapScale);
1055     checkException(env);
1056 }
1057
1058 void WebViewCore::needTouchEvents(bool need)
1059 {
1060     DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
1061     LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
1062
1063 #if ENABLE(TOUCH_EVENTS)
1064     if (m_forwardingTouchEvents == need)
1065         return;
1066
1067     JNIEnv* env = JSC::Bindings::getJNIEnv();
1068     env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_needTouchEvents, need);
1069     checkException(env);
1070
1071     m_forwardingTouchEvents = need;
1072 #endif
1073 }
1074
1075 void WebViewCore::requestKeyboardWithSelection(const WebCore::Node* node,
1076         int selStart, int selEnd)
1077 {
1078     DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
1079     LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
1080
1081     JNIEnv* env = JSC::Bindings::getJNIEnv();
1082     env->CallVoidMethod(m_javaGlue->object(env).get(),
1083             m_javaGlue->m_requestKeyboardWithSelection,
1084             reinterpret_cast<int>(node), selStart, selEnd, m_textGeneration);
1085     checkException(env);
1086 }
1087
1088 void WebViewCore::requestKeyboard(bool showKeyboard)
1089 {
1090     DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
1091     LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
1092
1093     JNIEnv* env = JSC::Bindings::getJNIEnv();
1094     env->CallVoidMethod(m_javaGlue->object(env).get(),
1095             m_javaGlue->m_requestKeyboard, showKeyboard);
1096     checkException(env);
1097 }
1098
1099 void WebViewCore::notifyProgressFinished()
1100 {
1101     DBG_NAV_LOG("call updateFrameCache");
1102     m_check_domtree_version = true;
1103     updateFrameCache();
1104     sendNotifyProgressFinished();
1105 }
1106
1107 void WebViewCore::doMaxScroll(CacheBuilder::Direction dir)
1108 {
1109     int dx = 0, dy = 0;
1110
1111     switch (dir) {
1112     case CacheBuilder::LEFT:
1113         dx = -m_maxXScroll;
1114         break;
1115     case CacheBuilder::UP:
1116         dy = -m_maxYScroll;
1117         break;
1118     case CacheBuilder::RIGHT:
1119         dx = m_maxXScroll;
1120         break;
1121     case CacheBuilder::DOWN:
1122         dy = m_maxYScroll;
1123         break;
1124     case CacheBuilder::UNINITIALIZED:
1125     default:
1126         LOG_ASSERT(0, "unexpected focus selector");
1127     }
1128     this->scrollBy(dx, dy, true);
1129 }
1130
1131 void WebViewCore::setScrollOffset(int moveGeneration, int userScrolled, int dx, int dy)
1132 {
1133     DBG_NAV_LOGD("{%d,%d} m_scrollOffset=(%d,%d), userScrolled=%d", dx, dy,
1134         m_scrollOffsetX, m_scrollOffsetY, userScrolled);
1135     if (m_scrollOffsetX != dx || m_scrollOffsetY != dy) {
1136         m_scrollOffsetX = dx;
1137         m_scrollOffsetY = dy;
1138         // The visible rect is located within our coordinate space so it
1139         // contains the actual scroll position. Setting the location makes hit
1140         // testing work correctly.
1141         m_mainFrame->view()->platformWidget()->setLocation(m_scrollOffsetX,
1142                 m_scrollOffsetY);
1143         if (userScrolled) {
1144             m_mainFrame->eventHandler()->sendScrollEvent();
1145         }
1146
1147         // update the currently visible screen
1148         sendPluginVisibleScreen();
1149     }
1150     gCursorBoundsMutex.lock();
1151     bool hasCursorBounds = m_hasCursorBounds;
1152     Frame* frame = (Frame*) m_cursorFrame;
1153     IntPoint location = m_cursorLocation;
1154     gCursorBoundsMutex.unlock();
1155     if (!hasCursorBounds)
1156         return;
1157     moveMouseIfLatest(moveGeneration, frame, location.x(), location.y());
1158 }
1159
1160 void WebViewCore::setGlobalBounds(int x, int y, int h, int v)
1161 {
1162     DBG_NAV_LOGD("{%d,%d}", x, y);
1163     m_mainFrame->view()->platformWidget()->setWindowBounds(x, y, h, v);
1164 }
1165
1166 void WebViewCore::setSizeScreenWidthAndScale(int width, int height,
1167     int textWrapWidth, float scale, int screenWidth, int screenHeight,
1168     int anchorX, int anchorY, bool ignoreHeight)
1169 {
1170     WebCoreViewBridge* window = m_mainFrame->view()->platformWidget();
1171     int ow = window->width();
1172     int oh = window->height();
1173     window->setSize(width, height);
1174     window->setVisibleSize(screenWidth, screenHeight);
1175     if (width != screenWidth) {
1176         m_mainFrame->view()->setUseFixedLayout(true);
1177         m_mainFrame->view()->setFixedLayoutSize(IntSize(width, height));
1178     } else {
1179         m_mainFrame->view()->setUseFixedLayout(false);
1180     }
1181     int osw = m_screenWidth;
1182     int osh = m_screenHeight;
1183     int otw = m_textWrapWidth;
1184     DBG_NAV_LOGD("old:(w=%d,h=%d,sw=%d,scale=%g) new:(w=%d,h=%d,sw=%d,scale=%g)",
1185         ow, oh, osw, m_scale, width, height, screenWidth, scale);
1186     m_screenWidth = screenWidth;
1187     m_screenHeight = screenHeight;
1188     m_textWrapWidth = textWrapWidth;
1189     if (scale >= 0) // negative means keep the current scale
1190         m_scale = scale;
1191     m_maxXScroll = screenWidth >> 2;
1192     m_maxYScroll = m_maxXScroll * height / width;
1193     if (ow != width || (!ignoreHeight && oh != height) || otw != textWrapWidth) {
1194         WebCore::RenderObject *r = m_mainFrame->contentRenderer();
1195         DBG_NAV_LOGD("renderer=%p view=(w=%d,h=%d)", r,
1196                 screenWidth, screenHeight);
1197         if (r) {
1198             WebCore::IntPoint anchorPoint = WebCore::IntPoint(anchorX, anchorY);
1199             DBG_NAV_LOGD("anchorX=%d anchorY=%d", anchorX, anchorY);
1200             RefPtr<WebCore::Node> node;
1201             WebCore::IntRect bounds;
1202             WebCore::IntPoint offset;
1203             // If the text wrap changed, it is probably zoom change or
1204             // orientation change. Try to keep the anchor at the same place.
1205             if (otw && textWrapWidth && otw != textWrapWidth) {
1206                 WebCore::HitTestResult hitTestResult =
1207                         m_mainFrame->eventHandler()-> hitTestResultAtPoint(
1208                                 anchorPoint, false);
1209                 node = hitTestResult.innerNode();
1210             }
1211             if (node) {
1212                 bounds = node->getRect();
1213                 DBG_NAV_LOGD("ob:(x=%d,y=%d,w=%d,h=%d)",
1214                     bounds.x(), bounds.y(), bounds.width(), bounds.height());
1215                 // sites like nytimes.com insert a non-standard tag <nyt_text>
1216                 // in the html. If it is the HitTestResult, it may have zero
1217                 // width and height. In this case, use its parent node.
1218                 if (bounds.width() == 0) {
1219                     node = node->parent();
1220                     if (node) {
1221                         bounds = node->getRect();
1222                         DBG_NAV_LOGD("found a zero width node and use its parent, whose ob:(x=%d,y=%d,w=%d,h=%d)",
1223                                 bounds.x(), bounds.y(), bounds.width(), bounds.height());
1224                     }
1225                 }
1226             }
1227             r->setNeedsLayoutAndPrefWidthsRecalc();
1228             m_mainFrame->view()->forceLayout();
1229             // scroll to restore current screen center
1230             if (node) {
1231                 const WebCore::IntRect& newBounds = node->getRect();
1232                 DBG_NAV_LOGD("nb:(x=%d,y=%d,w=%d,"
1233                     "h=%d)", newBounds.x(), newBounds.y(),
1234                     newBounds.width(), newBounds.height());
1235                 if ((osw && osh && bounds.width() && bounds.height())
1236                     && (bounds != newBounds)) {
1237                     WebCore::FrameView* view = m_mainFrame->view();
1238                     // force left align if width is not changed while height changed.
1239                     // the anchorPoint is probably at some white space in the node
1240                     // which is affected by text wrap around the screen width.
1241                     const bool leftAlign = (otw != textWrapWidth)
1242                         && (bounds.width() == newBounds.width())
1243                         && (bounds.height() != newBounds.height());
1244                     const float xPercentInDoc =
1245                         leftAlign ? 0.0 : (float) (anchorX - bounds.x()) / bounds.width();
1246                     const float xPercentInView =
1247                         leftAlign ? 0.0 : (float) (anchorX - m_scrollOffsetX) / osw;
1248                     const float yPercentInDoc = (float) (anchorY - bounds.y()) / bounds.height();
1249                     const float yPercentInView = (float) (anchorY - m_scrollOffsetY) / osh;
1250                     showRect(newBounds.x(), newBounds.y(), newBounds.width(),
1251                              newBounds.height(), view->contentsWidth(),
1252                              view->contentsHeight(),
1253                              xPercentInDoc, xPercentInView,
1254                              yPercentInDoc, yPercentInView);
1255                 }
1256             }
1257         }
1258     }
1259
1260     // update the currently visible screen as perceived by the plugin
1261     sendPluginVisibleScreen();
1262 }
1263
1264 void WebViewCore::dumpDomTree(bool useFile)
1265 {
1266 #ifdef ANDROID_DOM_LOGGING
1267     if (useFile)
1268         gDomTreeFile = fopen(DOM_TREE_LOG_FILE, "w");
1269     m_mainFrame->document()->showTreeForThis();
1270     if (gDomTreeFile) {
1271         fclose(gDomTreeFile);
1272         gDomTreeFile = 0;
1273     }
1274 #endif
1275 }
1276
1277 void WebViewCore::dumpRenderTree(bool useFile)
1278 {
1279 #ifdef ANDROID_DOM_LOGGING
1280     WTF::CString renderDump = WebCore::externalRepresentation(m_mainFrame).utf8();
1281     const char* data = renderDump.data();
1282     if (useFile) {
1283         gRenderTreeFile = fopen(RENDER_TREE_LOG_FILE, "w");
1284         DUMP_RENDER_LOGD("%s", data);
1285         fclose(gRenderTreeFile);
1286         gRenderTreeFile = 0;
1287     } else {
1288         // adb log can only output 1024 characters, so write out line by line.
1289         // exclude '\n' as adb log adds it for each output.
1290         int length = renderDump.length();
1291         for (int i = 0, last = 0; i < length; i++) {
1292             if (data[i] == '\n') {
1293                 if (i != last)
1294                     DUMP_RENDER_LOGD("%.*s", (i - last), &(data[last]));
1295                 last = i + 1;
1296             }
1297         }
1298     }
1299 #endif
1300 }
1301
1302 void WebViewCore::dumpNavTree()
1303 {
1304 #if DUMP_NAV_CACHE
1305     cacheBuilder().mDebug.print();
1306 #endif
1307 }
1308
1309 WebCore::HTMLAnchorElement* WebViewCore::retrieveAnchorElement(WebCore::Frame* frame, WebCore::Node* node)
1310 {
1311     if (!CacheBuilder::validNode(m_mainFrame, frame, node))
1312         return 0;
1313     if (!node->hasTagName(WebCore::HTMLNames::aTag))
1314         return 0;
1315     return static_cast<WebCore::HTMLAnchorElement*>(node);
1316 }
1317
1318 WTF::String WebViewCore::retrieveHref(WebCore::Frame* frame, WebCore::Node* node)
1319 {
1320     WebCore::HTMLAnchorElement* anchor = retrieveAnchorElement(frame, node);
1321     return anchor ? anchor->href() : WTF::String();
1322 }
1323
1324 WTF::String WebViewCore::retrieveAnchorText(WebCore::Frame* frame, WebCore::Node* node)
1325 {
1326     WebCore::HTMLAnchorElement* anchor = retrieveAnchorElement(frame, node);
1327     return anchor ? anchor->text() : WTF::String();
1328 }
1329
1330 WTF::String WebViewCore::requestLabel(WebCore::Frame* frame,
1331         WebCore::Node* node)
1332 {
1333     if (node && CacheBuilder::validNode(m_mainFrame, frame, node)) {
1334         RefPtr<WebCore::NodeList> list = node->document()->getElementsByTagName("label");
1335         unsigned length = list->length();
1336         for (unsigned i = 0; i < length; i++) {
1337             WebCore::HTMLLabelElement* label = static_cast<WebCore::HTMLLabelElement*>(
1338                     list->item(i));
1339             if (label->control() == node) {
1340                 Node* node = label;
1341                 String result;
1342                 while ((node = node->traverseNextNode(label))) {
1343                     if (node->isTextNode()) {
1344                         Text* textNode = static_cast<Text*>(node);
1345                         result += textNode->dataImpl();
1346                     }
1347                 }
1348                 return result;
1349             }
1350         }
1351     }
1352     return WTF::String();
1353 }
1354
1355 static bool isContentEditable(WebCore::Node* node)
1356 {
1357     if (!node) return false;
1358     return node->document()->frame()->selection()->isContentEditable();
1359 }
1360
1361 void WebViewCore::revealSelection()
1362 {
1363     WebCore::Node* focus = currentFocus();
1364     if (!focus)
1365         return;
1366     WebCore::RenderObject* renderer = focus->renderer();
1367     if ((!renderer || (!renderer->isTextField() && !renderer->isTextArea()))
1368         && !isContentEditable(focus))
1369         return;
1370     WebCore::Frame* focusedFrame = focus->document()->frame();
1371     WebFrame* webFrame = WebFrame::getWebFrame(focusedFrame);
1372     webFrame->setUserInitiatedAction(true);
1373     focusedFrame->selection()->revealSelection();
1374     webFrame->setUserInitiatedAction(false);
1375 }
1376
1377 void WebViewCore::updateCacheOnNodeChange()
1378 {
1379     gCursorBoundsMutex.lock();
1380     bool hasCursorBounds = m_hasCursorBounds;
1381     Frame* frame = (Frame*) m_cursorFrame;
1382     Node* node = (Node*) m_cursorNode;
1383     IntRect bounds = m_cursorHitBounds;
1384     gCursorBoundsMutex.unlock();
1385     if (!hasCursorBounds || !node)
1386         return;
1387     if (CacheBuilder::validNode(m_mainFrame, frame, node)) {
1388         RenderObject* renderer = node->renderer();
1389         if (renderer && renderer->style()->visibility() != HIDDEN) {
1390             IntRect absBox = renderer->absoluteBoundingBoxRect();
1391             int globalX, globalY;
1392             CacheBuilder::GetGlobalOffset(frame, &globalX, &globalY);
1393             absBox.move(globalX, globalY);
1394             if (absBox == bounds)
1395                 return;
1396             DBG_NAV_LOGD("absBox=(%d,%d,%d,%d) bounds=(%d,%d,%d,%d)",
1397                 absBox.x(), absBox.y(), absBox.width(), absBox.height(),
1398                 bounds.x(), bounds.y(), bounds.width(), bounds.height());
1399         }
1400     }
1401     DBG_NAV_LOGD("updateFrameCache node=%p", node);
1402     updateFrameCache();
1403 }
1404
1405 void WebViewCore::updateFrameCache()
1406 {
1407     if (!m_frameCacheOutOfDate) {
1408         DBG_NAV_LOG("!m_frameCacheOutOfDate");
1409         return;
1410     }
1411 #ifdef ANDROID_INSTRUMENT
1412     TimeCounterAuto counter(TimeCounter::WebViewCoreBuildNavTimeCounter);
1413 #endif
1414     m_frameCacheOutOfDate = false;
1415 #if DEBUG_NAV_UI
1416     m_now = SkTime::GetMSecs();
1417 #endif
1418     m_temp = new CachedRoot();
1419     m_temp->init(m_mainFrame, &m_history);
1420 #if USE(ACCELERATED_COMPOSITING)
1421     GraphicsLayerAndroid* graphicsLayer = graphicsRootLayer();
1422     if (graphicsLayer)
1423         m_temp->setRootLayer(graphicsLayer->contentLayer());
1424 #endif
1425     CacheBuilder& builder = cacheBuilder();
1426     WebCore::Settings* settings = m_mainFrame->page()->settings();
1427     builder.allowAllTextDetection();
1428 #ifdef ANDROID_META_SUPPORT
1429     if (settings) {
1430         if (!settings->formatDetectionAddress())
1431             builder.disallowAddressDetection();
1432         if (!settings->formatDetectionEmail())
1433             builder.disallowEmailDetection();
1434         if (!settings->formatDetectionTelephone())
1435             builder.disallowPhoneDetection();
1436     }
1437 #endif
1438     builder.buildCache(m_temp);
1439     m_tempPict = new SkPicture();
1440     recordPicture(m_tempPict);
1441     m_temp->setPicture(m_tempPict);
1442     m_temp->setTextGeneration(m_textGeneration);
1443     WebCoreViewBridge* window = m_mainFrame->view()->platformWidget();
1444     m_temp->setVisibleRect(WebCore::IntRect(m_scrollOffsetX,
1445         m_scrollOffsetY, window->width(), window->height()));
1446     gFrameCacheMutex.lock();
1447     delete m_frameCacheKit;
1448     delete m_navPictureKit;
1449     m_frameCacheKit = m_temp;
1450     m_navPictureKit = m_tempPict;
1451     m_updatedFrameCache = true;
1452 #if DEBUG_NAV_UI
1453     const CachedNode* cachedFocusNode = m_frameCacheKit->currentFocus();
1454     DBG_NAV_LOGD("cachedFocusNode=%d (nodePointer=%p)",
1455         cachedFocusNode ? cachedFocusNode->index() : 0,
1456         cachedFocusNode ? cachedFocusNode->nodePointer() : 0);
1457 #endif
1458     gFrameCacheMutex.unlock();
1459 }
1460
1461 void WebViewCore::updateFrameCacheIfLoading()
1462 {
1463     if (!m_check_domtree_version)
1464         updateFrameCache();
1465 }
1466
1467 struct TouchNodeData {
1468     Node* mNode;
1469     IntRect mBounds;
1470 };
1471
1472 // get the bounding box of the Node
1473 static IntRect getAbsoluteBoundingBox(Node* node) {
1474     IntRect rect;
1475     RenderObject* render = node->renderer();
1476     if (render->isRenderInline())
1477         rect = toRenderInline(render)->linesVisibleOverflowBoundingBox();
1478     else if (render->isBox())
1479         rect = toRenderBox(render)->visualOverflowRect();
1480     else if (render->isText())
1481         rect = toRenderText(render)->linesBoundingBox();
1482     else
1483         LOGE("getAbsoluteBoundingBox failed for node %p, name %s", node, render->renderName());
1484     FloatPoint absPos = render->localToAbsolute();
1485     rect.move(absPos.x(), absPos.y());
1486     return rect;
1487 }
1488
1489 // get the highlight rectangles for the touch point (x, y) with the slop
1490 Vector<IntRect> WebViewCore::getTouchHighlightRects(int x, int y, int slop)
1491 {
1492     Vector<IntRect> rects;
1493     m_mousePos = IntPoint(x - m_scrollOffsetX, y - m_scrollOffsetY);
1494     HitTestResult hitTestResult = m_mainFrame->eventHandler()->hitTestResultAtPoint(IntPoint(x, y),
1495             false, false, DontHitTestScrollbars, HitTestRequest::Active | HitTestRequest::ReadOnly, IntSize(slop, slop));
1496     if (!hitTestResult.innerNode() || !hitTestResult.innerNode()->inDocument()) {
1497         LOGE("Should not happen: no in document Node found");
1498         return rects;
1499     }
1500     const ListHashSet<RefPtr<Node> >& list = hitTestResult.rectBasedTestResult();
1501     if (list.isEmpty()) {
1502         LOGE("Should not happen: no rect-based-test nodes found");
1503         return rects;
1504     }
1505     Frame* frame = hitTestResult.innerNode()->document()->frame();
1506     Vector<TouchNodeData> nodeDataList;
1507     ListHashSet<RefPtr<Node> >::const_iterator last = list.end();
1508     for (ListHashSet<RefPtr<Node> >::const_iterator it = list.begin(); it != last; ++it) {
1509         // TODO: it seems reasonable to not search across the frame. Isn't it?
1510         // if the node is not in the same frame as the innerNode, skip it
1511         if (it->get()->document()->frame() != frame)
1512             continue;
1513         // traverse up the tree to find the first node that needs highlight
1514         bool found = false;
1515         Node* eventNode = it->get();
1516         while (eventNode) {
1517             RenderObject* render = eventNode->renderer();
1518             if (render->isBody() || render->isRenderView())
1519                 break;
1520             if (eventNode->supportsFocus()
1521                     || eventNode->hasEventListeners(eventNames().clickEvent)
1522                     || eventNode->hasEventListeners(eventNames().mousedownEvent)
1523                     || eventNode->hasEventListeners(eventNames().mouseupEvent)) {
1524                 found = true;
1525                 break;
1526             }
1527             // the nodes in the rectBasedTestResult() are ordered based on z-index during hit testing.
1528             // so do not search for the eventNode across explicit z-index border.
1529             // TODO: this is a hard one to call. z-index is quite complicated as its value only
1530             // matters when you compare two RenderLayer in the same hierarchy level. e.g. in
1531             // the following example, "b" is on the top as its z level is the highest. even "c"
1532             // has 100 as z-index, it is still below "d" as its parent has the same z-index as
1533             // "d" and logically before "d". Of course "a" is the lowest in the z level.
1534             //
1535             // z-index:auto "a"
1536             //   z-index:2 "b"
1537             //   z-index:1
1538             //     z-index:100 "c"
1539             //   z-index:1 "d"
1540             //
1541             // If the fat point touches everyone, the order in the list should be "b", "d", "c"
1542             // and "a". When we search for the event node for "b", we really don't want "a" as
1543             // in the z-order it is behind everything else.
1544             if (!render->style()->hasAutoZIndex())
1545                 break;
1546             eventNode = eventNode->parentNode();
1547         }
1548         // didn't find any eventNode, skip it
1549         if (!found)
1550             continue;
1551         // first quick check whether it is a duplicated node before computing bounding box
1552         Vector<TouchNodeData>::const_iterator nlast = nodeDataList.end();
1553         for (Vector<TouchNodeData>::const_iterator n = nodeDataList.begin(); n != nlast; ++n) {
1554             // found the same node, skip it
1555             if (eventNode == n->mNode) {
1556                 found = false;
1557                 break;
1558             }
1559         }
1560         if (!found)
1561             continue;
1562         // next check whether the node is fully covered by or fully covering another node.
1563         found = false;
1564         IntRect rect = getAbsoluteBoundingBox(eventNode);
1565         if (rect.isEmpty()) {
1566             // if the node's bounds is empty and it is not a ContainerNode, skip it.
1567             if (!eventNode->isContainerNode())
1568                 continue;
1569             // if the node's children are all positioned objects, its bounds can be empty.
1570             // Walk through the children to find the bounding box.
1571             Node* child = static_cast<const ContainerNode*>(eventNode)->firstChild();
1572             while (child) {
1573                 IntRect childrect;
1574                 if (child->renderer())
1575                     childrect = getAbsoluteBoundingBox(child);
1576                 if (!childrect.isEmpty()) {
1577                     rect.unite(childrect);
1578                     child = child->traverseNextSibling(eventNode);
1579                 } else
1580                     child = child->traverseNextNode(eventNode);
1581             }
1582         }
1583         for (int i = nodeDataList.size() - 1; i >= 0; i--) {
1584             TouchNodeData n = nodeDataList.at(i);
1585             // the new node is enclosing an existing node, skip it
1586             if (rect.contains(n.mBounds)) {
1587                 found = true;
1588                 break;
1589             }
1590             // the new node is fully inside an existing node, remove the existing node
1591             if (n.mBounds.contains(rect))
1592                 nodeDataList.remove(i);
1593         }
1594         if (!found) {
1595             TouchNodeData newNode;
1596             newNode.mNode = eventNode;
1597             newNode.mBounds = rect;
1598             nodeDataList.append(newNode);
1599         }
1600     }
1601     if (!nodeDataList.size())
1602         return rects;
1603     // finally select the node with the largest overlap with the fat point
1604     TouchNodeData final;
1605     final.mNode = 0;
1606     IntPoint docPos = frame->view()->windowToContents(m_mousePos);
1607     IntRect testRect(docPos.x() - slop, docPos.y() - slop, 2 * slop + 1, 2 * slop + 1);
1608     int area = 0;
1609     Vector<TouchNodeData>::const_iterator nlast = nodeDataList.end();
1610     for (Vector<TouchNodeData>::const_iterator n = nodeDataList.begin(); n != nlast; ++n) {
1611         IntRect rect = n->mBounds;
1612         rect.intersect(testRect);
1613         int a = rect.width() * rect.height();
1614         if (a > area) {
1615             final = *n;
1616             area = a;
1617         }
1618     }
1619     // now get the node's highlight rectangles in the page coordinate system
1620     if (final.mNode) {
1621         IntPoint frameAdjust;
1622         if (frame != m_mainFrame) {
1623             frameAdjust = frame->view()->contentsToWindow(IntPoint());
1624             frameAdjust.move(m_scrollOffsetX, m_scrollOffsetY);
1625         }
1626         if (final.mNode->isLink()) {
1627             // most of the links are inline instead of box style. So the bounding box is not
1628             // a good representation for the highlights. Get the list of rectangles instead.
1629             RenderObject* render = final.mNode->renderer();
1630             IntPoint offset = roundedIntPoint(render->localToAbsolute());
1631             render->absoluteRects(rects, offset.x() + frameAdjust.x(), offset.y() + frameAdjust.y());
1632             bool inside = false;
1633             int distance = INT_MAX;
1634             int newx = x, newy = y;
1635             int i = rects.size();
1636             while (i--) {
1637                 if (rects[i].isEmpty()) {
1638                     rects.remove(i);
1639                     continue;
1640                 }
1641                 // check whether the point (x, y) is inside one of the rectangles.
1642                 if (inside)
1643                     continue;
1644                 if (rects[i].contains(x, y)) {
1645                     inside = true;
1646                     continue;
1647                 }
1648                 if (x >= rects[i].x() && x < rects[i].right()) {
1649                     if (y < rects[i].y()) {
1650                         if (rects[i].y() - y < distance) {
1651                             newx = x;
1652                             newy = rects[i].y();
1653                             distance = rects[i].y() - y;
1654                         }
1655                     } else if (y >= rects[i].bottom()) {
1656                         if (y - rects[i].bottom() + 1 < distance) {
1657                             newx = x;
1658                             newy = rects[i].bottom() - 1;
1659                             distance = y - rects[i].bottom() + 1;
1660                         }
1661                     }
1662                 } else if (y >= rects[i].y() && y < rects[i].bottom()) {
1663                     if (x < rects[i].x()) {
1664                         if (rects[i].x() - x < distance) {
1665                             newx = rects[i].x();
1666                             newy = y;
1667                             distance = rects[i].x() - x;
1668                         }
1669                     } else if (x >= rects[i].right()) {
1670                         if (x - rects[i].right() + 1 < distance) {
1671                             newx = rects[i].right() - 1;
1672                             newy = y;
1673                             distance = x - rects[i].right() + 1;
1674                         }
1675                     }
1676                 }
1677             }
1678             if (!rects.isEmpty()) {
1679                 if (!inside) {
1680                     // if neither x nor y has overlap, just pick the top/left of the first rectangle
1681                     if (newx == x && newy == y) {
1682                         newx = rects[0].x();
1683                         newy = rects[0].y();
1684                     }
1685                     m_mousePos.setX(newx - m_scrollOffsetX);
1686                     m_mousePos.setY(newy - m_scrollOffsetY);
1687                     DBG_NAV_LOGD("Move x/y from (%d, %d) to (%d, %d) scrollOffset is (%d, %d)",
1688                             x, y, m_mousePos.x() + m_scrollOffsetX, m_mousePos.y() + m_scrollOffsetY,
1689                             m_scrollOffsetX, m_scrollOffsetY);
1690                 }
1691                 return rects;
1692             }
1693         }
1694         IntRect rect = final.mBounds;
1695         rect.move(frameAdjust.x(), frameAdjust.y());
1696         rects.append(rect);
1697         // adjust m_mousePos if it is not inside the returned highlight rectangle
1698         testRect.move(frameAdjust.x(), frameAdjust.y());
1699         testRect.intersect(rect);
1700         if (!testRect.contains(x, y)) {
1701             m_mousePos = testRect.center();
1702             m_mousePos.move(-m_scrollOffsetX, -m_scrollOffsetY);
1703             DBG_NAV_LOGD("Move x/y from (%d, %d) to (%d, %d) scrollOffset is (%d, %d)",
1704                     x, y, m_mousePos.x() + m_scrollOffsetX, m_mousePos.y() + m_scrollOffsetY,
1705                     m_scrollOffsetX, m_scrollOffsetY);
1706         }
1707     }
1708     return rects;
1709 }
1710
1711 ///////////////////////////////////////////////////////////////////////////////
1712
1713 void WebViewCore::addPlugin(PluginWidgetAndroid* w)
1714 {
1715 //    SkDebugf("----------- addPlugin %p", w);
1716     /* The plugin must be appended to the end of the array. This ensures that if
1717        the plugin is added while iterating through the array (e.g. sendEvent(...))
1718        that the iteration process is not corrupted.
1719      */
1720     *m_plugins.append() = w;
1721 }
1722
1723 void WebViewCore::removePlugin(PluginWidgetAndroid* w)
1724 {
1725 //    SkDebugf("----------- removePlugin %p", w);
1726     int index = m_plugins.find(w);
1727     if (index < 0) {
1728         SkDebugf("--------------- pluginwindow not found! %p\n", w);
1729     } else {
1730         m_plugins.removeShuffle(index);
1731     }
1732 }
1733
1734 bool WebViewCore::isPlugin(PluginWidgetAndroid* w) const
1735 {
1736     return m_plugins.find(w) >= 0;
1737 }
1738
1739 void WebViewCore::invalPlugin(PluginWidgetAndroid* w)
1740 {
1741     const double PLUGIN_INVAL_DELAY = 1.0 / 60;
1742
1743     if (!m_pluginInvalTimer.isActive()) {
1744         m_pluginInvalTimer.startOneShot(PLUGIN_INVAL_DELAY);
1745     }
1746 }
1747
1748 void WebViewCore::drawPlugins()
1749 {
1750     SkRegion inval; // accumualte what needs to be redrawn
1751     PluginWidgetAndroid** iter = m_plugins.begin();
1752     PluginWidgetAndroid** stop = m_plugins.end();
1753
1754     for (; iter < stop; ++iter) {
1755         PluginWidgetAndroid* w = *iter;
1756         SkIRect dirty;
1757         if (w->isDirty(&dirty)) {
1758             w->draw();
1759             inval.op(dirty, SkRegion::kUnion_Op);
1760         }
1761     }
1762
1763     if (!inval.isEmpty()) {
1764         // inval.getBounds() is our rectangle
1765         const SkIRect& bounds = inval.getBounds();
1766         WebCore::IntRect r(bounds.fLeft, bounds.fTop,
1767                            bounds.width(), bounds.height());
1768         this->viewInvalidate(r);
1769     }
1770 }
1771
1772 void WebViewCore::notifyPluginsOnFrameLoad(const Frame* frame) {
1773     // if frame is the parent then notify all plugins
1774     if (!frame->tree()->parent()) {
1775         // trigger an event notifying the plugins that the page has loaded
1776         ANPEvent event;
1777         SkANP::InitEvent(&event, kLifecycle_ANPEventType);
1778         event.data.lifecycle.action = kOnLoad_ANPLifecycleAction;
1779         sendPluginEvent(event);
1780     }
1781     // else if frame's parent has completed
1782     else if (!frame->tree()->parent()->loader()->isLoading()) {
1783         // send to all plugins who have this frame in their heirarchy
1784         PluginWidgetAndroid** iter = m_plugins.begin();
1785         PluginWidgetAndroid** stop = m_plugins.end();
1786         for (; iter < stop; ++iter) {
1787             Frame* currentFrame = (*iter)->pluginView()->parentFrame();
1788             while (currentFrame) {
1789                 if (frame == currentFrame) {
1790                     ANPEvent event;
1791                     SkANP::InitEvent(&event, kLifecycle_ANPEventType);
1792                     event.data.lifecycle.action = kOnLoad_ANPLifecycleAction;
1793                     (*iter)->sendEvent(event);
1794                     break;
1795                 }
1796                 currentFrame = currentFrame->tree()->parent();
1797             }
1798         }
1799     }
1800 }
1801
1802 void WebViewCore::sendPluginVisibleScreen()
1803 {
1804     /* We may want to cache the previous values and only send the notification
1805        to the plugin in the event that one of the values has changed.
1806      */
1807
1808     ANPRectI visibleRect;
1809     visibleRect.left = m_scrollOffsetX;
1810     visibleRect.top = m_scrollOffsetY;
1811     visibleRect.right = m_scrollOffsetX + m_screenWidth;
1812     visibleRect.bottom = m_scrollOffsetY + m_screenHeight;
1813
1814     PluginWidgetAndroid** iter = m_plugins.begin();
1815     PluginWidgetAndroid** stop = m_plugins.end();
1816     for (; iter < stop; ++iter) {
1817         (*iter)->setVisibleScreen(visibleRect, m_scale);
1818     }
1819 }
1820
1821 void WebViewCore::sendPluginEvent(const ANPEvent& evt)
1822 {
1823     /* The list of plugins may be manipulated as we iterate through the list.
1824        This implementation allows for the addition of new plugins during an
1825        iteration, but may fail if a plugin is removed. Currently, there are not
1826        any use cases where a plugin is deleted while processing this loop, but
1827        if it does occur we will have to use an alternate data structure and/or
1828        iteration mechanism.
1829      */
1830     for (int x = 0; x < m_plugins.count(); x++) {
1831         m_plugins[x]->sendEvent(evt);
1832     }
1833 }
1834
1835 PluginWidgetAndroid* WebViewCore::getPluginWidget(NPP npp)
1836 {
1837     PluginWidgetAndroid** iter = m_plugins.begin();
1838     PluginWidgetAndroid** stop = m_plugins.end();
1839     for (; iter < stop; ++iter) {
1840         if ((*iter)->pluginView()->instance() == npp) {
1841             return (*iter);
1842         }
1843     }
1844     return NULL;
1845 }
1846
1847 static PluginView* nodeIsPlugin(Node* node) {
1848     RenderObject* renderer = node->renderer();
1849     if (renderer && renderer->isWidget()) {
1850         Widget* widget = static_cast<RenderWidget*>(renderer)->widget();
1851         if (widget && widget->isPluginView())
1852             return static_cast<PluginView*>(widget);
1853     }
1854     return 0;
1855 }
1856
1857 Node* WebViewCore::cursorNodeIsPlugin() {
1858     gCursorBoundsMutex.lock();
1859     bool hasCursorBounds = m_hasCursorBounds;
1860     Frame* frame = (Frame*) m_cursorFrame;
1861     Node* node = (Node*) m_cursorNode;
1862     gCursorBoundsMutex.unlock();
1863     if (hasCursorBounds && CacheBuilder::validNode(m_mainFrame, frame, node)
1864             && nodeIsPlugin(node)) {
1865         return node;
1866     }
1867     return 0;
1868 }
1869
1870 ///////////////////////////////////////////////////////////////////////////////
1871 void WebViewCore::moveMouseIfLatest(int moveGeneration,
1872     WebCore::Frame* frame, int x, int y)
1873 {
1874     DBG_NAV_LOGD("m_moveGeneration=%d moveGeneration=%d"
1875         " frame=%p x=%d y=%d",
1876         m_moveGeneration, moveGeneration, frame, x, y);
1877     if (m_moveGeneration > moveGeneration) {
1878         DBG_NAV_LOGD("m_moveGeneration=%d > moveGeneration=%d",
1879             m_moveGeneration, moveGeneration);
1880         return; // short-circuit if a newer move has already been generated
1881     }
1882     m_lastGeneration = moveGeneration;
1883     moveMouse(frame, x, y);
1884 }
1885
1886 void WebViewCore::moveFocus(WebCore::Frame* frame, WebCore::Node* node)
1887 {
1888     DBG_NAV_LOGD("frame=%p node=%p", frame, node);
1889     if (!node || !CacheBuilder::validNode(m_mainFrame, frame, node)
1890             || !node->isElementNode())
1891         return;
1892     // Code borrowed from FocusController::advanceFocus
1893     WebCore::FocusController* focusController
1894             = m_mainFrame->page()->focusController();
1895     WebCore::Document* oldDoc
1896             = focusController->focusedOrMainFrame()->document();
1897     if (oldDoc->focusedNode() == node)
1898         return;
1899     if (node->document() != oldDoc)
1900         oldDoc->setFocusedNode(0);
1901     focusController->setFocusedFrame(frame);
1902     static_cast<WebCore::Element*>(node)->focus(false);
1903 }
1904
1905 // Update mouse position
1906 void WebViewCore::moveMouse(WebCore::Frame* frame, int x, int y)
1907 {
1908     DBG_NAV_LOGD("frame=%p x=%d y=%d scrollOffset=(%d,%d)", frame,
1909         x, y, m_scrollOffsetX, m_scrollOffsetY);
1910     if (!frame || CacheBuilder::validNode(m_mainFrame, frame, NULL) == false)
1911         frame = m_mainFrame;
1912     // mouse event expects the position in the window coordinate
1913     m_mousePos = WebCore::IntPoint(x - m_scrollOffsetX, y - m_scrollOffsetY);
1914     // validNode will still return true if the node is null, as long as we have
1915     // a valid frame.  Do not want to make a call on frame unless it is valid.
1916     WebCore::PlatformMouseEvent mouseEvent(m_mousePos, m_mousePos,
1917         WebCore::NoButton, WebCore::MouseEventMoved, 1, false, false, false,
1918         false, WTF::currentTime());
1919     frame->eventHandler()->handleMouseMoveEvent(mouseEvent);
1920     updateCacheOnNodeChange();
1921 }
1922
1923 void WebViewCore::setSelection(int start, int end)
1924 {
1925     WebCore::Node* focus = currentFocus();
1926     if (!focus)
1927         return;
1928     WebCore::RenderObject* renderer = focus->renderer();
1929     if (!renderer || (!renderer->isTextField() && !renderer->isTextArea()))
1930         return;
1931     if (start > end) {
1932         int temp = start;
1933         start = end;
1934         end = temp;
1935     }
1936     // Tell our EditorClient that this change was generated from the UI, so it
1937     // does not need to echo it to the UI.
1938     EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
1939             m_mainFrame->editor()->client());
1940     client->setUiGeneratedSelectionChange(true);
1941     setSelectionRange(focus, start, end);
1942     client->setUiGeneratedSelectionChange(false);
1943     WebCore::Frame* focusedFrame = focus->document()->frame();
1944     bool isPasswordField = false;
1945     if (focus->isElementNode()) {
1946         WebCore::Element* element = static_cast<WebCore::Element*>(focus);
1947         if (WebCore::InputElement* inputElement = WebCore::toInputElement(element))
1948             isPasswordField = static_cast<WebCore::HTMLInputElement*>(inputElement)->isPasswordField();
1949     }
1950     // For password fields, this is done in the UI side via
1951     // bringPointIntoView, since the UI does the drawing.
1952     if (renderer->isTextArea() || !isPasswordField)
1953         focusedFrame->selection()->revealSelection();
1954 }
1955
1956 String WebViewCore::modifySelection(const int direction, const int axis)
1957 {
1958     DOMSelection* selection = m_mainFrame->domWindow()->getSelection();
1959     if (selection->rangeCount() > 1)
1960         selection->removeAllRanges();
1961     switch (axis) {
1962     case AXIS_CHARACTER:
1963     case AXIS_WORD:
1964     case AXIS_SENTENCE:
1965         return modifySelectionTextNavigationAxis(selection, direction, axis);
1966     case AXIS_HEADING:
1967     case AXIS_SIBLING:
1968     case AXIS_PARENT_FIRST_CHILD:
1969     case AXIS_DOCUMENT:
1970         return modifySelectionDomNavigationAxis(selection, direction, axis);
1971     default:
1972         LOGE("Invalid navigation axis: %d", axis);
1973         return String();
1974     }
1975 }
1976
1977 String WebViewCore::modifySelectionTextNavigationAxis(DOMSelection* selection, int direction, int axis)
1978 {
1979     String directionString;
1980     if (direction == DIRECTION_FORWARD)
1981         directionString = "forward";
1982     else if (direction == DIRECTION_BACKWARD)
1983         directionString = "backward";
1984     else {
1985         LOGE("Invalid direction: %d", direction);
1986         return String();
1987     }
1988     String axisString;
1989     if (axis == AXIS_CHARACTER)
1990         axisString = "character";
1991     else if (axis == AXIS_WORD)
1992         axisString = "word";
1993     else // axis == AXIS_SENTENCE
1994         axisString = "sentence";
1995
1996     // TODO: Add support of IFrames.
1997     HTMLElement* body = m_mainFrame->document()->body();
1998
1999     Node* focusNode = 0;
2000     if (m_currentNodeDomNavigationAxis
2001             && CacheBuilder::validNode(m_mainFrame, m_mainFrame, m_currentNodeDomNavigationAxis)) {
2002         focusNode = m_currentNodeDomNavigationAxis;
2003         m_currentNodeDomNavigationAxis = 0;
2004         do {
2005             focusNode = (direction == DIRECTION_FORWARD) ?
2006                     focusNode->traverseNextNode(body) :
2007                     focusNode->traversePreviousNode(body);
2008         } while (focusNode && focusNode->isTextNode());
2009     } else
2010         focusNode = (selection->focusNode()) ? selection->focusNode() : currentFocus();
2011
2012     Text* currentNode = 0;
2013     if (!focusNode) {
2014         // we have no selection so start from the body or its recursively last child
2015         focusNode = (direction == DIRECTION_FORWARD) ? body : body->lastDescendant();
2016         if (focusNode->isTextNode())
2017             currentNode = static_cast<Text*>(focusNode);
2018         else
2019             currentNode = traverseNonEmptyNonWhitespaceTextNode(focusNode, body, direction);
2020         if (!setSelection(selection, currentNode, direction))
2021             return String();
2022     } else if (focusNode->isElementNode()) {
2023         // find a non-empty text node in the current direction
2024         currentNode = traverseNonEmptyNonWhitespaceTextNode(focusNode, body, direction);
2025         if (!setSelection(selection, currentNode, direction))
2026             return String();
2027     } else {
2028         currentNode = static_cast<Text*>(focusNode);
2029         if (direction == DIRECTION_FORWARD) {
2030             // if end of non-whitespace text go to the next non-empty text node
2031             int higherIndex = (selection->focusOffset() > selection->anchorOffset()) ?
2032                     selection->focusOffset() : selection->anchorOffset();
2033             String suffix = currentNode->data().substring(higherIndex, currentNode->length());
2034             if (suffix.isEmpty() || suffix.stripWhiteSpace().isEmpty()) {
2035                 currentNode = traverseNonEmptyNonWhitespaceTextNode(currentNode, body, direction);
2036                 if (!setSelection(selection, currentNode, direction))
2037                     return String();
2038             } else {
2039               ExceptionCode ec = 0;
2040                 selection->collapseToEnd(ec);
2041                 if (ec)
2042                     LOGE("Error while collapsing selection. Error code: %d", ec);
2043             }
2044         } else {
2045             // if beginning of non-whitespace text go to the previous non-empty text node
2046             int lowerIndex = (selection->focusOffset() > selection->anchorOffset()) ?
2047                     selection->anchorOffset() : selection->focusOffset();
2048             String prefix = currentNode->data().substring(0, lowerIndex);
2049             if (prefix.isEmpty() || prefix.stripWhiteSpace().isEmpty()) {
2050                 currentNode = traverseNonEmptyNonWhitespaceTextNode(currentNode, body, direction);
2051                 if (!setSelection(selection, currentNode, direction))
2052                     return String();
2053             } else {
2054                 ExceptionCode ec = 0;
2055                 selection->collapseToStart(ec);
2056                 if (ec)
2057                     LOGE("Error while collapsing selection. Error code: %d", ec);
2058             }
2059         }
2060     }
2061
2062     // extend the selection - loop as an insurance it does not get stuck
2063     currentNode = static_cast<Text*>(selection->focusNode());
2064     int focusOffset = selection->focusOffset();
2065     while (true) {
2066         selection->modify("extend", directionString, axisString);
2067         if (selection->focusNode() != currentNode || selection->focusOffset() != focusOffset)
2068             break;
2069         currentNode = traverseNonEmptyNonWhitespaceTextNode(currentNode, body, direction);
2070         focusOffset = (direction == DIRECTION_FORWARD) ? 0 : currentNode->data().length();
2071         // setSelection returns false if currentNode is 0 => the loop always terminates
2072         if (!setSelection(selection, currentNode, direction))
2073             return String();
2074     }
2075
2076     if (direction == DIRECTION_FORWARD) {
2077         // enforce the anchor node is a text node
2078         if (selection->anchorNode()->isElementNode()) {
2079             if (!setSelection(selection, selection->focusNode(), selection->focusNode(), 0,
2080                               selection->focusOffset()))
2081                 return String();
2082         }
2083         // enforce the focus node is a text node
2084         if (selection->focusNode()->isElementNode()) {
2085             int endOffset = static_cast<Text*>(selection->anchorNode())->length(); // cast is safe
2086             if (!setSelection(selection, selection->anchorNode(), selection->anchorNode(),
2087                               selection->anchorOffset(), endOffset))
2088                 return String();
2089         }
2090     } else {
2091         // enforce the focus node is a text node
2092         if (selection->focusNode()->isElementNode()) {
2093             if (!setSelection(selection, selection->anchorNode(), selection->anchorNode(), 0,
2094                               selection->anchorOffset()))
2095                 return String();
2096         }
2097         // enforce the anchor node is a text node
2098         if (selection->anchorNode()->isElementNode()) {
2099             int endOffset = static_cast<Text*>(selection->focusNode())->length(); // cast is safe
2100             if (!setSelection(selection, selection->focusNode(), selection->focusNode(),
2101                               selection->focusOffset(), endOffset))
2102                 return String();
2103         }
2104     }
2105
2106     tryFocusInlineSelectionElement(selection);
2107     // TODO (svetoslavganov): Draw the selected text in the WebView - a-la-Android
2108     String markup = formatMarkup(selection).stripWhiteSpace();
2109     LOGD("Selection markup: %s", markup.utf8().data());
2110     return markup;
2111 }
2112
2113 bool WebViewCore::setSelection(DOMSelection* selection, Text* textNode, int direction)
2114 {
2115     if (!textNode)
2116         return false;
2117     int offset = (direction == DIRECTION_FORWARD) ? 0 : textNode->length();
2118     if (!setSelection(selection, textNode, textNode, offset, offset))
2119         return false;
2120     return true;
2121 }
2122
2123 bool WebViewCore::setSelection(DOMSelection* selection, Node* startNode, Node* endNode, int startOffset, int endOffset)
2124 {
2125     if (!selection || (!startNode && !endNode))
2126         return false;
2127     ExceptionCode ec = 0;
2128     PassRefPtr<Range> rangeRef = selection->getRangeAt(0, ec);
2129     if (ec) {
2130         ec = 0;
2131         rangeRef = m_mainFrame->document()->createRange();
2132     }
2133     if (startNode)
2134         rangeRef->setStart(PassRefPtr<Node>(startNode), startOffset, ec);
2135     if (ec)
2136         return false;
2137     if (endNode)
2138         rangeRef->setEnd(PassRefPtr<Node>(endNode), endOffset, ec);
2139     if (ec)
2140         return false;
2141     selection->removeAllRanges();
2142     selection->addRange(rangeRef.get());
2143     return true;
2144 }
2145
2146 Text* WebViewCore::traverseNonEmptyNonWhitespaceTextNode(Node* fromNode, Node* toNode, int direction)
2147 {
2148     Node* currentNode = fromNode;
2149     do {
2150         if (direction == DIRECTION_FORWARD)
2151             currentNode = currentNode->traverseNextNode(toNode);
2152         else
2153             currentNode = currentNode->traversePreviousNode(toNode);
2154     } while (currentNode && (!currentNode->isTextNode()
2155             || isEmptyOrOnlyWhitespaceTextNode(currentNode)));
2156     return static_cast<Text*>(currentNode);
2157 }
2158
2159 bool WebViewCore::isEmptyOrOnlyWhitespaceTextNode(Node* node)
2160 {
2161     return (node->isTextNode()
2162           && (static_cast<Text*>(node)->length() == 0
2163           || static_cast<Text*>(node)->containsOnlyWhitespace()));
2164 }
2165
2166 String WebViewCore::modifySelectionDomNavigationAxis(DOMSelection* selection, int direction, int axis)
2167 {
2168     // TODO: Add support of IFrames.
2169     HTMLElement* body = m_mainFrame->document()->body();
2170     if (!m_currentNodeDomNavigationAxis && selection->focusNode()) {
2171         m_currentNodeDomNavigationAxis = selection->focusNode();
2172         selection->empty();
2173         if (m_currentNodeDomNavigationAxis->isTextNode())
2174             m_currentNodeDomNavigationAxis = m_currentNodeDomNavigationAxis->parentNode();
2175     }
2176     if (!m_currentNodeDomNavigationAxis)
2177         m_currentNodeDomNavigationAxis = currentFocus();
2178     if (!m_currentNodeDomNavigationAxis
2179             || !CacheBuilder::validNode(m_mainFrame, m_mainFrame, m_currentNodeDomNavigationAxis))
2180         m_currentNodeDomNavigationAxis = body;
2181     Node* currentNode = m_currentNodeDomNavigationAxis;
2182     if (axis == AXIS_HEADING) {
2183         if (currentNode == body && direction == DIRECTION_BACKWARD)
2184             currentNode = currentNode->lastDescendant();
2185         do {
2186             if (direction == DIRECTION_FORWARD)
2187                 currentNode = currentNode->traverseNextNode(body);
2188             else
2189                 currentNode = currentNode->traversePreviousNode(body);
2190         } while (currentNode && (currentNode->isTextNode() || !isVisible(currentNode)
2191                 || !isHeading(currentNode)));
2192     } else if (axis == AXIS_PARENT_FIRST_CHILD) {
2193         if (direction == DIRECTION_FORWARD) {
2194             currentNode = currentNode->firstChild();
2195             while (currentNode && (currentNode->isTextNode() || !isVisible(currentNode)))
2196                 currentNode = currentNode->nextSibling();
2197         } else {
2198             do {
2199                 if (currentNode == body)
2200                     return String();
2201                 currentNode = currentNode->parentNode();
2202             } while (currentNode && (currentNode->isTextNode() || !isVisible(currentNode)));
2203         }
2204     } else if (axis == AXIS_SIBLING) {
2205         do {
2206             if (direction == DIRECTION_FORWARD)
2207                 currentNode = currentNode->nextSibling();
2208             else {
2209                 if (currentNode == body)
2210                     return String();
2211                 currentNode = currentNode->previousSibling();
2212             }
2213         } while (currentNode && (currentNode->isTextNode() || !isVisible(currentNode)));
2214     } else if (axis == AXIS_DOCUMENT) {
2215         currentNode = body;
2216         if (direction == DIRECTION_FORWARD)
2217             currentNode = currentNode->lastDescendant();
2218     } else {
2219         LOGE("Invalid axis: %d", axis);
2220         return String();
2221     }
2222     if (currentNode) {
2223         m_currentNodeDomNavigationAxis = currentNode;
2224         focusIfFocusableAndNotTextInput(selection, currentNode);
2225         // TODO (svetoslavganov): Draw the selected text in the WebView - a-la-Android
2226         String selectionString = createMarkup(currentNode);
2227         LOGD("Selection markup: %s", selectionString.utf8().data());
2228         return selectionString;
2229     }
2230     return String();
2231 }
2232
2233 bool WebViewCore::isHeading(Node* node)
2234 {
2235     if (node->hasTagName(WebCore::HTMLNames::h1Tag)
2236             || node->hasTagName(WebCore::HTMLNames::h2Tag)
2237             || node->hasTagName(WebCore::HTMLNames::h3Tag)
2238             || node->hasTagName(WebCore::HTMLNames::h4Tag)
2239             || node->hasTagName(WebCore::HTMLNames::h5Tag)
2240             || node->hasTagName(WebCore::HTMLNames::h6Tag)) {
2241         return true;
2242     }
2243
2244     if (node->isElementNode()) {
2245         Element* element = static_cast<Element*>(node);
2246         String roleAttribute = element->getAttribute(WebCore::HTMLNames::roleAttr).string();
2247         if (equalIgnoringCase(roleAttribute, "heading"))
2248             return true;
2249     }
2250
2251     return false;
2252 }
2253
2254 bool WebViewCore::isVisible(Node* node)
2255 {
2256     if (!node->isStyledElement())
2257         return false;
2258     RenderStyle* style = node->computedStyle();
2259     return (style->display() != NONE && style->visibility() != HIDDEN);
2260 }
2261
2262 String WebViewCore::formatMarkup(DOMSelection* selection)
2263 {
2264     ExceptionCode ec = 0;
2265     PassRefPtr<Range> rangeRef = selection->getRangeAt(0, ec);
2266     if (ec) {
2267         LOGE("Error accessing the first selection range. Error code: %d", ec);
2268         return String();
2269     }
2270     // TODO: This breaks in certain cases - WebKit bug. Figure out and work around it
2271     String markup = createMarkup(rangeRef.get());
2272     int fromIdx = markup.find("<span class=\"Apple-style-span\"");
2273     while (fromIdx > -1) {
2274         unsigned toIdx = markup.find(">");
2275         markup = markup.replace(fromIdx, toIdx - fromIdx + 1, "");
2276         markup = markup.replace("</span>", "");
2277         fromIdx = markup.find("<span class=\"Apple-style-span\"");
2278     }
2279     return markup;
2280 }
2281
2282 void WebViewCore::tryFocusInlineSelectionElement(DOMSelection* selection)
2283 {
2284     Node* currentNode = selection->anchorNode();
2285     Node* endNode = selection->focusNode();
2286     while (currentNode) {
2287         if (focusIfFocusableAndNotTextInput(selection, currentNode))
2288             return;
2289         currentNode = currentNode->traverseNextNode(endNode);
2290     }
2291 }
2292
2293 bool WebViewCore::focusIfFocusableAndNotTextInput(DOMSelection* selection, Node* node)
2294 {
2295     // TODO (svetoslavganov): Synchronize Android and WebKit focus
2296     if (node->isFocusable()) {
2297         WebCore::RenderObject* renderer = node->renderer();
2298         if (!renderer || (!renderer->isTextField() && !renderer->isTextArea())) {
2299             // restore the selection after focus workaround for
2300             // the FIXME in Element.cpp#updateFocusAppearance
2301             ExceptionCode ec = 0;
2302             PassRefPtr<Range> rangeRef = selection->getRangeAt(0, ec);
2303             moveFocus(m_mainFrame, node);
2304             if (rangeRef)
2305                 selection->addRange(rangeRef.get());
2306             return true;
2307         }
2308     }
2309     return false;
2310 }
2311
2312 void WebViewCore::deleteSelection(int start, int end, int textGeneration)
2313 {
2314     setSelection(start, end);
2315     if (start == end)
2316         return;
2317     WebCore::Node* focus = currentFocus();
2318     if (!focus)
2319         return;
2320     // Prevent our editor client from passing a message to change the
2321     // selection.
2322     EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
2323             m_mainFrame->editor()->client());
2324     client->setUiGeneratedSelectionChange(true);
2325     PlatformKeyboardEvent down(AKEYCODE_DEL, 0, 0, true, false, false, false);
2326     PlatformKeyboardEvent up(AKEYCODE_DEL, 0, 0, false, false, false, false);
2327     key(down);
2328     key(up);
2329     client->setUiGeneratedSelectionChange(false);
2330     m_textGeneration = textGeneration;
2331 }
2332
2333 void WebViewCore::replaceTextfieldText(int oldStart,
2334         int oldEnd, const WTF::String& replace, int start, int end,
2335         int textGeneration)
2336 {
2337     WebCore::Node* focus = currentFocus();
2338     if (!focus)
2339         return;
2340     setSelection(oldStart, oldEnd);
2341     // Prevent our editor client from passing a message to change the
2342     // selection.
2343     EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
2344             m_mainFrame->editor()->client());
2345     client->setUiGeneratedSelectionChange(true);
2346     WebCore::TypingCommand::insertText(focus->document(), replace,
2347         false);
2348     client->setUiGeneratedSelectionChange(false);
2349     // setSelection calls revealSelection, so there is no need to do it here.
2350     setSelection(start, end);
2351     m_textGeneration = textGeneration;
2352 }
2353
2354 void WebViewCore::passToJs(int generation, const WTF::String& current,
2355     const PlatformKeyboardEvent& event)
2356 {
2357     WebCore::Node* focus = currentFocus();
2358     if (!focus) {
2359         DBG_NAV_LOG("!focus");
2360         clearTextEntry();
2361         return;
2362     }
2363     WebCore::RenderObject* renderer = focus->renderer();
2364     if (!renderer || (!renderer->isTextField() && !renderer->isTextArea())) {
2365         DBG_NAV_LOGD("renderer==%p || not text", renderer);
2366         clearTextEntry();
2367         return;
2368     }
2369     // Block text field updates during a key press.
2370     m_blockTextfieldUpdates = true;
2371     // Also prevent our editor client from passing a message to change the
2372     // selection.
2373     EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
2374             m_mainFrame->editor()->client());
2375     client->setUiGeneratedSelectionChange(true);
2376     key(event);
2377     client->setUiGeneratedSelectionChange(false);
2378     m_blockTextfieldUpdates = false;
2379     m_textGeneration = generation;
2380     WebCore::RenderTextControl* renderText =
2381         static_cast<WebCore::RenderTextControl*>(renderer);
2382     WTF::String test = renderText->text();
2383     if (test != current) {
2384         // If the text changed during the key event, update the UI text field.
2385         updateTextfield(focus, false, test);
2386     } else {
2387         DBG_NAV_LOG("test == current");
2388     }
2389     // Now that the selection has settled down, send it.
2390     updateTextSelection();
2391 }
2392
2393 void WebViewCore::scrollFocusedTextInput(float xPercent, int y)
2394 {
2395     WebCore::Node* focus = currentFocus();
2396     if (!focus) {
2397         DBG_NAV_LOG("!focus");
2398         clearTextEntry();
2399         return;
2400     }
2401     WebCore::RenderObject* renderer = focus->renderer();
2402     if (!renderer || (!renderer->isTextField() && !renderer->isTextArea())) {
2403         DBG_NAV_LOGD("renderer==%p || not text", renderer);
2404         clearTextEntry();
2405         return;
2406     }
2407     WebCore::RenderTextControl* renderText =
2408         static_cast<WebCore::RenderTextControl*>(renderer);
2409     int x = (int) (xPercent * (renderText->scrollWidth() -
2410         renderText->clientWidth()));
2411     DBG_NAV_LOGD("x=%d y=%d xPercent=%g scrollW=%d clientW=%d", x, y,
2412         xPercent, renderText->scrollWidth(), renderText->clientWidth());
2413     renderText->setScrollLeft(x);
2414     renderText->setScrollTop(y);
2415 }
2416
2417 void WebViewCore::setFocusControllerActive(bool active)
2418 {
2419     m_mainFrame->page()->focusController()->setActive(active);
2420 }
2421
2422 void WebViewCore::saveDocumentState(WebCore::Frame* frame)
2423 {
2424     if (!CacheBuilder::validNode(m_mainFrame, frame, 0))
2425         frame = m_mainFrame;
2426     WebCore::HistoryItem *item = frame->loader()->history()->currentItem();
2427
2428     // item can be null when there is no offical URL for the current page. This happens
2429     // when the content is loaded using with WebCoreFrameBridge::LoadData() and there
2430     // is no failing URL (common case is when content is loaded using data: scheme)
2431     if (item) {
2432         item->setDocumentState(frame->document()->formElementsState());
2433     }
2434 }
2435
2436 // Convert a WTF::String into an array of characters where the first
2437 // character represents the length, for easy conversion to java.
2438 static uint16_t* stringConverter(const WTF::String& text)
2439 {
2440     size_t length = text.length();
2441     uint16_t* itemName = new uint16_t[length+1];
2442     itemName[0] = (uint16_t)length;
2443     uint16_t* firstChar = &(itemName[1]);
2444     memcpy((void*)firstChar, text.characters(), sizeof(UChar)*length);
2445     return itemName;
2446 }
2447
2448 // Response to dropdown created for a listbox.
2449 class ListBoxReply : public WebCoreReply {
2450 public:
2451     ListBoxReply(WebCore::HTMLSelectElement* select, WebCore::Frame* frame, WebViewCore* view)
2452         : m_select(select)
2453         , m_frame(frame)
2454         , m_viewImpl(view)
2455     {}
2456
2457     // Response used if the listbox only allows single selection.
2458     // index is listIndex of the selected item, or -1 if nothing is selected.
2459     virtual void replyInt(int index)
2460     {
2461         if (-2 == index) {
2462             // Special value for cancel. Do nothing.
2463             return;
2464         }
2465         // If the select element no longer exists, due to a page change, etc,
2466         // silently return.
2467         if (!m_select || !CacheBuilder::validNode(m_viewImpl->m_mainFrame,
2468                 m_frame, m_select))
2469             return;
2470         // Use a pointer to HTMLSelectElement's superclass, where
2471         // listToOptionIndex is public.
2472         SelectElement* selectElement = m_select;
2473         int optionIndex = selectElement->listToOptionIndex(index);
2474         m_select->setSelectedIndex(optionIndex, true);
2475         m_select->dispatchFormControlChangeEvent();
2476         m_viewImpl->contentInvalidate(m_select->getRect());
2477     }
2478
2479     // Response if the listbox allows multiple selection.  array stores the listIndices
2480     // of selected positions.
2481     virtual void replyIntArray(const int* array, int count)
2482     {
2483         // If the select element no longer exists, due to a page change, etc,
2484         // silently return.
2485         if (!m_select || !CacheBuilder::validNode(m_viewImpl->m_mainFrame,
2486                 m_frame, m_select))
2487             return;
2488
2489         // If count is 1 or 0, use replyInt.
2490         SkASSERT(count > 1);
2491
2492         const WTF::Vector<Element*>& items = m_select->listItems();
2493         int totalItems = static_cast<int>(items.size());
2494         // Keep track of the position of the value we are comparing against.
2495         int arrayIndex = 0;
2496         // The value we are comparing against.
2497         int selection = array[arrayIndex];
2498         WebCore::HTMLOptionElement* option;
2499         for (int listIndex = 0; listIndex < totalItems; listIndex++) {
2500             if (items[listIndex]->hasLocalName(WebCore::HTMLNames::optionTag)) {
2501                 option = static_cast<WebCore::HTMLOptionElement*>(
2502                         items[listIndex]);
2503                 if (listIndex == selection) {
2504                     option->setSelectedState(true);
2505                     arrayIndex++;
2506                     if (arrayIndex == count)
2507                         selection = -1;
2508                     else
2509                         selection = array[arrayIndex];
2510                 } else
2511                     option->setSelectedState(false);
2512             }
2513         }
2514         m_select->dispatchFormControlChangeEvent();
2515         m_viewImpl->contentInvalidate(m_select->getRect());
2516     }
2517 private:
2518     // The select element associated with this listbox.
2519     WebCore::HTMLSelectElement* m_select;
2520     // The frame of this select element, to verify that it is valid.
2521     WebCore::Frame* m_frame;
2522     // For calling invalidate and checking the select element's validity
2523     WebViewCore* m_viewImpl;
2524 };
2525
2526 // Create an array of java Strings.
2527 static jobjectArray makeLabelArray(JNIEnv* env, const uint16_t** labels, size_t count)
2528 {
2529     jclass stringClass = env->FindClass("java/lang/String");
2530     LOG_ASSERT(stringClass, "Could not find java/lang/String");
2531     jobjectArray array = env->NewObjectArray(count, stringClass, 0);
2532     LOG_ASSERT(array, "Could not create new string array");
2533
2534     for (size_t i = 0; i < count; i++) {
2535         jobject newString = env->NewString(&labels[i][1], labels[i][0]);
2536         env->SetObjectArrayElement(array, i, newString);
2537         env->DeleteLocalRef(newString);
2538         checkException(env);
2539     }
2540     env->DeleteLocalRef(stringClass);
2541     return array;
2542 }
2543
2544 void WebViewCore::openFileChooser(PassRefPtr<WebCore::FileChooser> chooser) {
2545     if (!chooser)
2546         return;
2547     JNIEnv* env = JSC::Bindings::getJNIEnv();
2548
2549     WTF::String acceptType = chooser->acceptTypes();
2550     jstring jAcceptType = WtfStringToJstring(env, acceptType);
2551     jstring jName = (jstring) env->CallObjectMethod(
2552             m_javaGlue->object(env).get(), m_javaGlue->m_openFileChooser, jAcceptType);
2553     checkException(env);
2554     env->DeleteLocalRef(jAcceptType);
2555
2556     const UChar* string = static_cast<const UChar*>(env->GetStringChars(jName, NULL));
2557
2558     if (!string)
2559         return;
2560
2561     WTF::String webcoreString = jstringToWtfString(env, jName);
2562     env->ReleaseStringChars(jName, string);
2563
2564     if (webcoreString.length())
2565         chooser->chooseFile(webcoreString);
2566 }
2567
2568 void WebViewCore::listBoxRequest(WebCoreReply* reply, const uint16_t** labels, size_t count, const int enabled[], size_t enabledCount,
2569         bool multiple, const int selected[], size_t selectedCountOrSelection)
2570 {
2571     // If m_popupReply is not null, then we already have a list showing.
2572     if (m_popupReply != 0)
2573         return;
2574
2575     LOG_ASSERT(m_javaGlue->m_obj, "No java widget associated with this view!");
2576
2577     // Create an array of java Strings for the drop down.
2578     JNIEnv* env = JSC::Bindings::getJNIEnv();
2579     jobjectArray labelArray = makeLabelArray(env, labels, count);
2580
2581     // Create an array determining whether each item is enabled.
2582     jintArray enabledArray = env->NewIntArray(enabledCount);
2583     checkException(env);
2584     jint* ptrArray = env->GetIntArrayElements(enabledArray, 0);
2585     checkException(env);
2586     for (size_t i = 0; i < enabledCount; i++) {
2587         ptrArray[i] = enabled[i];
2588     }
2589     env->ReleaseIntArrayElements(enabledArray, ptrArray, 0);
2590     checkException(env);
2591
2592     if (multiple) {
2593         // Pass up an array representing which items are selected.
2594         jintArray selectedArray = env->NewIntArray(selectedCountOrSelection);
2595         checkException(env);
2596         jint* selArray = env->GetIntArrayElements(selectedArray, 0);
2597         checkException(env);
2598         for (size_t i = 0; i < selectedCountOrSelection; i++) {
2599             selArray[i] = selected[i];
2600         }
2601         env->ReleaseIntArrayElements(selectedArray, selArray, 0);
2602
2603         env->CallVoidMethod(m_javaGlue->object(env).get(),
2604                 m_javaGlue->m_requestListBox, labelArray, enabledArray,
2605                 selectedArray);
2606         env->DeleteLocalRef(selectedArray);
2607     } else {
2608         // Pass up the single selection.
2609         env->CallVoidMethod(m_javaGlue->object(env).get(),
2610                 m_javaGlue->m_requestSingleListBox, labelArray, enabledArray,
2611                 selectedCountOrSelection);
2612     }
2613
2614     env->DeleteLocalRef(labelArray);
2615     env->DeleteLocalRef(enabledArray);
2616     checkException(env);
2617
2618     Retain(reply);
2619     m_popupReply = reply;
2620 }
2621
2622 bool WebViewCore::key(const PlatformKeyboardEvent& event)
2623 {
2624     WebCore::EventHandler* eventHandler;
2625     WebCore::Node* focusNode = currentFocus();
2626     DBG_NAV_LOGD("keyCode=%s unichar=%d focusNode=%p",
2627         event.keyIdentifier().utf8().data(), event.unichar(), focusNode);
2628     if (focusNode) {
2629         WebCore::Frame* frame = focusNode->document()->frame();
2630         WebFrame* webFrame = WebFrame::getWebFrame(frame);
2631         eventHandler = frame->eventHandler();
2632         VisibleSelection old = frame->selection()->selection();
2633         bool handled = eventHandler->keyEvent(event);
2634         if (isContentEditable(focusNode)) {
2635             // keyEvent will return true even if the contentEditable did not
2636             // change its selection.  In the case that it does not, we want to
2637             // return false so that the key will be sent back to our navigation
2638             // system.
2639             handled = frame->selection()->selection() != old;
2640         }
2641         return handled;
2642     } else {
2643         eventHandler = m_mainFrame->eventHandler();
2644     }
2645     return eventHandler->keyEvent(event);
2646 }
2647
2648 // For when the user clicks the trackball
2649 void WebViewCore::click(WebCore::Frame* frame, WebCore::Node* node) {
2650     if (!node) {
2651         WebCore::IntPoint pt = m_mousePos;
2652         pt.move(m_scrollOffsetX, m_scrollOffsetY);
2653         WebCore::HitTestResult hitTestResult = m_mainFrame->eventHandler()->
2654                 hitTestResultAtPoint(pt, false);
2655         node = hitTestResult.innerNode();
2656         frame = node->document()->frame();
2657         DBG_NAV_LOGD("m_mousePos=(%d,%d) m_scrollOffset=(%d,%d) pt=(%d,%d)"
2658             " node=%p", m_mousePos.x(), m_mousePos.y(),
2659             m_scrollOffsetX, m_scrollOffsetY, pt.x(), pt.y(), node);
2660     }
2661     if (node) {
2662         EditorClientAndroid* client
2663                 = static_cast<EditorClientAndroid*>(
2664                 m_mainFrame->editor()->client());
2665         client->setShouldChangeSelectedRange(false);
2666         handleMouseClick(frame, node);
2667         client->setShouldChangeSelectedRange(true);
2668     }
2669 }
2670
2671 #if USE(ACCELERATED_COMPOSITING)
2672 GraphicsLayerAndroid* WebViewCore::graphicsRootLayer() const
2673 {
2674     RenderView* contentRenderer = m_mainFrame->contentRenderer();
2675     if (!contentRenderer)
2676         return 0;
2677     return static_cast<GraphicsLayerAndroid*>(
2678           contentRenderer->compositor()->rootPlatformLayer());
2679 }
2680 #endif
2681
2682 bool WebViewCore::handleTouchEvent(int action, Vector<IntPoint>& points, int metaState)
2683 {
2684     bool preventDefault = false;
2685
2686 #if USE(ACCELERATED_COMPOSITING)
2687     GraphicsLayerAndroid* rootLayer = graphicsRootLayer();
2688     if (rootLayer)
2689       rootLayer->pauseDisplay(true);
2690 #endif
2691
2692 #if ENABLE(TOUCH_EVENTS) // Android
2693     WebCore::TouchEventType type = WebCore::TouchStart;
2694     WebCore::PlatformTouchPoint::State touchState = WebCore::PlatformTouchPoint::TouchPressed;
2695     switch (action) {
2696     case 0: // MotionEvent.ACTION_DOWN
2697     case 5: // MotionEvent.ACTION_POINTER_DOWN
2698         type = WebCore::TouchStart;
2699         break;
2700     case 1: // MotionEvent.ACTION_UP
2701     case 6: // MotionEvent.ACTION_POINTER_UP
2702         type = WebCore::TouchEnd;
2703         touchState = WebCore::PlatformTouchPoint::TouchReleased;
2704         break;
2705     case 2: // MotionEvent.ACTION_MOVE
2706         type = WebCore::TouchMove;
2707         touchState = WebCore::PlatformTouchPoint::TouchMoved;
2708         break;
2709     case 3: // MotionEvent.ACTION_CANCEL
2710         type = WebCore::TouchCancel;
2711         touchState = WebCore::PlatformTouchPoint::TouchCancelled;
2712         break;
2713     case 0x100: // WebViewCore.ACTION_LONGPRESS
2714         type = WebCore::TouchLongPress;
2715         touchState = WebCore::PlatformTouchPoint::TouchPressed;
2716         break;
2717     case 0x200: // WebViewCore.ACTION_DOUBLETAP
2718         type = WebCore::TouchDoubleTap;
2719         touchState = WebCore::PlatformTouchPoint::TouchPressed;
2720         break;
2721     default:
2722         // We do not support other kinds of touch event inside WebCore
2723         // at the moment.
2724         LOGW("Java passed a touch event type that we do not support in WebCore: %d", action);
2725         return 0;
2726     }
2727
2728     // Track previous touch and if stationary set the state.
2729     for (unsigned c = 0; c < points.size(); c++) {
2730         points[c].setX(points[c].x() - m_scrollOffsetX);
2731         points[c].setY(points[c].y() - m_scrollOffsetY);
2732     }
2733     WebCore::PlatformTouchEvent te(points, type, touchState, metaState);
2734     preventDefault = m_mainFrame->eventHandler()->handleTouchEvent(te);
2735 #endif
2736
2737 #if USE(ACCELERATED_COMPOSITING)
2738     if (rootLayer)
2739       rootLayer->pauseDisplay(false);
2740 #endif
2741     return preventDefault;
2742 }
2743
2744 void WebViewCore::touchUp(int touchGeneration,
2745     WebCore::Frame* frame, WebCore::Node* node, int x, int y)
2746 {
2747     if (touchGeneration == 0) {
2748         // m_mousePos should be set in getTouchHighlightRects()
2749         WebCore::HitTestResult hitTestResult = m_mainFrame->eventHandler()->hitTestResultAtPoint(m_mousePos, false);
2750         node = hitTestResult.innerNode();
2751         if (node)
2752             frame = node->document()->frame();
2753         else
2754             frame = 0;
2755         DBG_NAV_LOGD("touch up on (%d, %d), scrollOffset is (%d, %d), node:%p, frame:%p", m_mousePos.x() + m_scrollOffsetX, m_mousePos.y() + m_scrollOffsetY, m_scrollOffsetX, m_scrollOffsetY, node, frame);
2756     } else {
2757         if (m_touchGeneration > touchGeneration) {
2758             DBG_NAV_LOGD("m_touchGeneration=%d > touchGeneration=%d"
2759                 " x=%d y=%d", m_touchGeneration, touchGeneration, x, y);
2760             return; // short circuit if a newer touch has been generated
2761         }
2762         // This moves m_mousePos to the correct place, and handleMouseClick uses
2763         // m_mousePos to determine where the click happens.
2764         moveMouse(frame, x, y);
2765         m_lastGeneration = touchGeneration;
2766     }
2767     if (frame && CacheBuilder::validNode(m_mainFrame, frame, 0)) {
2768         frame->loader()->resetMultipleFormSubmissionProtection();
2769     }
2770     DBG_NAV_LOGD("touchGeneration=%d handleMouseClick frame=%p node=%p"
2771         " x=%d y=%d", touchGeneration, frame, node, x, y);
2772     handleMouseClick(frame, node);
2773 }
2774
2775 // Return the RenderLayer for the given RenderObject only if the layer is
2776 // composited and it contains a scrollable content layer.
2777 static WebCore::RenderLayer* getLayerFromRenderer(
2778         WebCore::RenderObject* renderer, LayerAndroid** aLayer)
2779 {
2780     if (!renderer)
2781         return 0;
2782     WebCore::RenderLayer* layer = renderer->enclosingSelfPaintingLayer();
2783     if (!layer || !layer->backing())
2784         return 0;
2785     GraphicsLayerAndroid* graphicsLayer =
2786             static_cast<GraphicsLayerAndroid*>(layer->backing()->graphicsLayer());
2787     if (!graphicsLayer)
2788         return 0;
2789     LayerAndroid* layerAndroid = graphicsLayer->contentLayer();
2790     if (!layerAndroid || !layerAndroid->contentIsScrollable())
2791         return 0;
2792     *aLayer = layerAndroid;
2793     return layer;
2794 }
2795
2796 // Scroll the RenderLayer associated with a scrollable div element.  This is
2797 // done so that the node is visible when it is clicked.
2798 static void scrollLayer(WebCore::RenderObject* renderer, WebCore::IntPoint* pos)
2799 {
2800     LayerAndroid* aLayer;
2801     WebCore::RenderLayer* layer = getLayerFromRenderer(renderer, &aLayer);
2802     if (!layer)
2803         return;
2804     WebCore::IntRect absBounds = renderer->absoluteBoundingBoxRect();
2805     // Do not include the outline when moving the node's bounds.
2806     WebCore::IntRect layerBounds = layer->renderer()->absoluteBoundingBoxRect();
2807
2808     // Move the node's bounds into the layer's coordinates.
2809     absBounds.move(-layerBounds.x(), -layerBounds.y());
2810
2811     int diffX = layer->scrollXOffset();
2812     int diffY = layer->scrollYOffset();
2813     // Scroll the layer to the node's position.  The false parameters tell the
2814     // layer not to invalidate.
2815     layer->scrollToOffset(absBounds.x(), absBounds.y(), false, true);
2816     diffX = layer->scrollXOffset() - diffX;
2817     diffY = layer->scrollYOffset() - diffY;
2818
2819     // Update the mouse position to the layer offset.
2820     pos->move(-diffX, -diffY);
2821 }
2822
2823 // Common code for both clicking with the trackball and touchUp
2824 bool WebViewCore::handleMouseClick(WebCore::Frame* framePtr, WebCore::Node* nodePtr)
2825 {
2826     m_lastClickWasOnTextInput = false;
2827     bool valid = framePtr == NULL
2828             || CacheBuilder::validNode(m_mainFrame, framePtr, nodePtr);
2829     WebFrame* webFrame = WebFrame::getWebFrame(m_mainFrame);
2830     if (valid && nodePtr) {
2831     // Need to special case area tags because an image map could have an area element in the middle
2832     // so when attempting to get the default, the point chosen would be follow the wrong link.
2833         if (nodePtr->hasTagName(WebCore::HTMLNames::areaTag)) {
2834             webFrame->setUserInitiatedAction(true);
2835             nodePtr->dispatchSimulatedClick(0, true, true);
2836             webFrame->setUserInitiatedAction(false);
2837             DBG_NAV_LOG("area");
2838             return true;
2839         }
2840
2841         WebCore::RenderObject* renderer = nodePtr->renderer();
2842         if (renderer && (renderer->isMenuList() || renderer->isListBox())) {
2843             WebCore::HTMLSelectElement* select = static_cast<WebCore::HTMLSelectElement*>(nodePtr);
2844             const WTF::Vector<WebCore::Element*>& listItems = select->listItems();
2845             SkTDArray<const uint16_t*> names;
2846             // Possible values for enabledArray.  Keep in Sync with values in
2847             // InvokeListBox.Container in WebView.java
2848             enum OptionStatus {
2849                 OPTGROUP = -1,
2850                 OPTION_DISABLED = 0,
2851                 OPTION_ENABLED = 1,
2852             };
2853             SkTDArray<int> enabledArray;
2854             SkTDArray<int> selectedArray;
2855             int size = listItems.size();
2856             bool multiple = select->multiple();
2857             for (int i = 0; i < size; i++) {
2858                 if (listItems[i]->hasTagName(WebCore::HTMLNames::optionTag)) {
2859                     WebCore::HTMLOptionElement* option = static_cast<WebCore::HTMLOptionElement*>(listItems[i]);
2860                     *names.append() = stringConverter(option->textIndentedToRespectGroupLabel());
2861                     *enabledArray.append() = option->disabled() ? OPTION_DISABLED : OPTION_ENABLED;
2862                     if (multiple && option->selected())
2863                         *selectedArray.append() = i;
2864                 } else if (listItems[i]->hasTagName(WebCore::HTMLNames::optgroupTag)) {
2865                     WebCore::HTMLOptGroupElement* optGroup = static_cast<WebCore::HTMLOptGroupElement*>(listItems[i]);
2866                     *names.append() = stringConverter(optGroup->groupLabelText());
2867                     *enabledArray.append() = OPTGROUP;
2868                 }
2869             }
2870             WebCoreReply* reply = new ListBoxReply(select, select->document()->frame(), this);
2871             // Use a pointer to HTMLSelectElement's superclass, where
2872             // optionToListIndex is public.
2873             SelectElement* selectElement = select;
2874             listBoxRequest(reply, names.begin(), size, enabledArray.begin(), enabledArray.count(),
2875                     multiple, selectedArray.begin(), multiple ? selectedArray.count() :
2876                     selectElement->optionToListIndex(select->selectedIndex()));
2877             DBG_NAV_LOG("menu list");
2878             return true;
2879         }
2880     }
2881     if (!valid || !framePtr)
2882         framePtr = m_mainFrame;
2883     if (nodePtr && valid) {
2884         scrollLayer(nodePtr->renderer(), &m_mousePos);
2885         if (isContentEditable(nodePtr) || (nodePtr->renderer()
2886                 && (nodePtr->renderer()-> isTextArea() || nodePtr->renderer()->isTextField()))) {
2887             // The user clicked on a text input field.  If this causes a blur event
2888             // on a different text input, do not hide the keyboard in formDidBlur
2889             m_lastClickWasOnTextInput = true;
2890         }
2891     }
2892     webFrame->setUserInitiatedAction(true);
2893     WebCore::PlatformMouseEvent mouseDown(m_mousePos, m_mousePos, WebCore::LeftButton,
2894             WebCore::MouseEventPressed, 1, false, false, false, false,
2895             WTF::currentTime());
2896     // ignore the return from as it will return true if the hit point can trigger selection change
2897     framePtr->eventHandler()->handleMousePressEvent(mouseDown);
2898     WebCore::PlatformMouseEvent mouseUp(m_mousePos, m_mousePos, WebCore::LeftButton,
2899             WebCore::MouseEventReleased, 1, false, false, false, false,
2900             WTF::currentTime());
2901     bool handled = framePtr->eventHandler()->handleMouseReleaseEvent(mouseUp);
2902     webFrame->setUserInitiatedAction(false);
2903
2904     m_lastClickWasOnTextInput = false;
2905
2906     // If the user clicked on a textfield, make the focusController active
2907     // so we show the blinking cursor.
2908     WebCore::Node* focusNode = currentFocus();
2909     DBG_NAV_LOGD("m_mousePos={%d,%d} focusNode=%p handled=%s", m_mousePos.x(),
2910         m_mousePos.y(), focusNode, handled ? "true" : "false");
2911     if (focusNode) {
2912         WebCore::RenderObject* renderer = focusNode->renderer();
2913         if (renderer && (renderer->isTextField() || renderer->isTextArea())) {
2914             bool ime = !(static_cast<WebCore::HTMLInputElement*>(focusNode))
2915                     ->readOnly();
2916             if (ime) {
2917                 RenderTextControl* rtc
2918                         = static_cast<RenderTextControl*> (renderer);
2919                 requestKeyboardWithSelection(focusNode, rtc->selectionStart(),
2920                         rtc->selectionEnd());
2921             } else {
2922                 requestKeyboard(false);
2923             }
2924         } else {
2925             // If the selection is contentEditable, show the keyboard so the
2926             // user can type.  Otherwise hide the keyboard because no text
2927             // input is needed.
2928             if (isContentEditable(focusNode)) {
2929                 requestKeyboard(true);
2930             } else {
2931                 clearTextEntry();
2932             }
2933         }
2934     } else {
2935         // There is no focusNode, so the keyboard is not needed.
2936         clearTextEntry();
2937     }
2938     return handled;
2939 }
2940
2941 void WebViewCore::popupReply(int index)
2942 {
2943     if (m_popupReply) {
2944         m_popupReply->replyInt(index);
2945         Release(m_popupReply);
2946         m_popupReply = 0;
2947     }
2948 }
2949
2950 void WebViewCore::popupReply(const int* array, int count)
2951 {
2952     if (m_popupReply) {
2953         m_popupReply->replyIntArray(array, count);
2954         Release(m_popupReply);
2955         m_popupReply = NULL;
2956     }
2957 }
2958
2959 void WebViewCore::formDidBlur(const WebCore::Node* node)
2960 {
2961     // This blur is the result of clicking on a different input.  Do not hide
2962     // the keyboard, since it will just be opened again.
2963     if (m_lastClickWasOnTextInput) return;
2964
2965     JNIEnv* env = JSC::Bindings::getJNIEnv();
2966     env->CallVoidMethod(m_javaGlue->object(env).get(),
2967             m_javaGlue->m_formDidBlur, reinterpret_cast<int>(node));
2968     checkException(env);
2969 }
2970
2971 void WebViewCore::addMessageToConsole(const WTF::String& message, unsigned int lineNumber, const WTF::String& sourceID, int msgLevel) {
2972     JNIEnv* env = JSC::Bindings::getJNIEnv();
2973     jstring jMessageStr = WtfStringToJstring(env, message);
2974     jstring jSourceIDStr = WtfStringToJstring(env, sourceID);
2975     env->CallVoidMethod(m_javaGlue->object(env).get(),
2976             m_javaGlue->m_addMessageToConsole, jMessageStr, lineNumber,
2977             jSourceIDStr, msgLevel);
2978     env->DeleteLocalRef(jMessageStr);
2979     env->DeleteLocalRef(jSourceIDStr);
2980     checkException(env);
2981 }
2982
2983 void WebViewCore::jsAlert(const WTF::String& url, const WTF::String& text)
2984 {
2985     JNIEnv* env = JSC::Bindings::getJNIEnv();
2986     jstring jInputStr = WtfStringToJstring(env, text);
2987     jstring jUrlStr = WtfStringToJstring(env, url);
2988     env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsAlert, jUrlStr, jInputStr);
2989     env->DeleteLocalRef(jInputStr);
2990     env->DeleteLocalRef(jUrlStr);
2991     checkException(env);
2992 }
2993
2994 void WebViewCore::exceededDatabaseQuota(const WTF::String& url, const WTF::String& databaseIdentifier, const unsigned long long currentQuota, unsigned long long estimatedSize)
2995 {
2996 #if ENABLE(DATABASE)
2997     JNIEnv* env = JSC::Bindings::getJNIEnv();
2998     jstring jDatabaseIdentifierStr = WtfStringToJstring(env, databaseIdentifier);
2999     jstring jUrlStr = WtfStringToJstring(env, url);
3000     env->CallVoidMethod(m_javaGlue->object(env).get(),
3001             m_javaGlue->m_exceededDatabaseQuota, jUrlStr,
3002             jDatabaseIdentifierStr, currentQuota, estimatedSize);
3003     env->DeleteLocalRef(jDatabaseIdentifierStr);
3004     env->DeleteLocalRef(jUrlStr);
3005     checkException(env);
3006 #endif
3007 }
3008
3009 void WebViewCore::reachedMaxAppCacheSize(const unsigned long long spaceNeeded)
3010 {
3011 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
3012     JNIEnv* env = JSC::Bindings::getJNIEnv();
3013     env->CallVoidMethod(m_javaGlue->object(env).get(),
3014             m_javaGlue->m_reachedMaxAppCacheSize, spaceNeeded);
3015     checkException(env);
3016 #endif
3017 }
3018
3019 void WebViewCore::populateVisitedLinks(WebCore::PageGroup* group)
3020 {
3021     m_groupForVisitedLinks = group;
3022     JNIEnv* env = JSC::Bindings::getJNIEnv();
3023     env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_populateVisitedLinks);
3024     checkException(env);
3025 }
3026
3027 void WebViewCore::geolocationPermissionsShowPrompt(const WTF::String& origin)
3028 {
3029     JNIEnv* env = JSC::Bindings::getJNIEnv();
3030     jstring originString = WtfStringToJstring(env, origin);
3031     env->CallVoidMethod(m_javaGlue->object(env).get(),
3032                         m_javaGlue->m_geolocationPermissionsShowPrompt,
3033                         originString);
3034     env->DeleteLocalRef(originString);
3035     checkException(env);
3036 }
3037
3038 void WebViewCore::geolocationPermissionsHidePrompt()
3039 {
3040     JNIEnv* env = JSC::Bindings::getJNIEnv();
3041     env->CallVoidMethod(m_javaGlue->object(env).get(),
3042                         m_javaGlue->m_geolocationPermissionsHidePrompt);
3043     checkException(env);
3044 }
3045
3046 jobject WebViewCore::getDeviceMotionService()
3047 {
3048     JNIEnv* env = JSC::Bindings::getJNIEnv();
3049     jobject object = env->CallObjectMethod(m_javaGlue->object(env).get(),
3050                                            m_javaGlue->m_getDeviceMotionService);
3051     checkException(env);
3052     return object;
3053 }
3054
3055 jobject WebViewCore::getDeviceOrientationService()
3056 {
3057     JNIEnv* env = JSC::Bindings::getJNIEnv();
3058     jobject object = env->CallObjectMethod(m_javaGlue->object(env).get(),
3059                                            m_javaGlue->m_getDeviceOrientationService);
3060     checkException(env);
3061     return object;
3062 }
3063
3064 bool WebViewCore::jsConfirm(const WTF::String& url, const WTF::String& text)
3065 {
3066     JNIEnv* env = JSC::Bindings::getJNIEnv();
3067     jstring jInputStr = WtfStringToJstring(env, text);
3068     jstring jUrlStr = WtfStringToJstring(env, url);
3069     jboolean result = env->CallBooleanMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsConfirm, jUrlStr, jInputStr);
3070     env->DeleteLocalRef(jInputStr);
3071     env->DeleteLocalRef(jUrlStr);
3072     checkException(env);
3073     return result;
3074 }
3075
3076 bool WebViewCore::jsPrompt(const WTF::String& url, const WTF::String& text, const WTF::String& defaultValue, WTF::String& result)
3077 {
3078     JNIEnv* env = JSC::Bindings::getJNIEnv();
3079     jstring jInputStr = WtfStringToJstring(env, text);
3080     jstring jDefaultStr = WtfStringToJstring(env, defaultValue);
3081     jstring jUrlStr = WtfStringToJstring(env, url);
3082     jstring returnVal = static_cast<jstring>(env->CallObjectMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsPrompt, jUrlStr, jInputStr, jDefaultStr));
3083     env->DeleteLocalRef(jInputStr);
3084     env->DeleteLocalRef(jDefaultStr);
3085     env->DeleteLocalRef(jUrlStr);
3086     checkException(env);
3087
3088     // If returnVal is null, it means that the user cancelled the dialog.
3089     if (!returnVal)
3090         return false;
3091
3092     result = jstringToWtfString(env, returnVal);
3093     return true;
3094 }
3095
3096 bool WebViewCore::jsUnload(const WTF::String& url, const WTF::String& message)
3097 {
3098     JNIEnv* env = JSC::Bindings::getJNIEnv();
3099     jstring jInputStr = WtfStringToJstring(env, message);
3100     jstring jUrlStr = WtfStringToJstring(env, url);
3101     jboolean result = env->CallBooleanMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsUnload, jUrlStr, jInputStr);
3102     env->DeleteLocalRef(jInputStr);
3103     env->DeleteLocalRef(jUrlStr);
3104     checkException(env);
3105     return result;
3106 }
3107
3108 bool WebViewCore::jsInterrupt()
3109 {
3110     JNIEnv* env = JSC::Bindings::getJNIEnv();
3111     jboolean result = env->CallBooleanMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsInterrupt);
3112     checkException(env);
3113     return result;
3114 }
3115
3116 AutoJObject
3117 WebViewCore::getJavaObject()
3118 {
3119     return getRealObject(JSC::Bindings::getJNIEnv(), m_javaGlue->m_obj);
3120 }
3121
3122 jobject
3123 WebViewCore::getWebViewJavaObject()
3124 {
3125     JNIEnv* env = JSC::Bindings::getJNIEnv();
3126     return env->GetObjectField(m_javaGlue->object(env).get(), gWebViewCoreFields.m_webView);
3127 }
3128
3129 void WebViewCore::updateTextSelection() {
3130     WebCore::Node* focusNode = currentFocus();
3131     if (!focusNode)
3132         return;
3133     RenderObject* renderer = focusNode->renderer();
3134     if (!renderer || (!renderer->isTextArea() && !renderer->isTextField()))
3135         return;
3136     RenderTextControl* rtc = static_cast<RenderTextControl*>(renderer);
3137     JNIEnv* env = JSC::Bindings::getJNIEnv();
3138     env->CallVoidMethod(m_javaGlue->object(env).get(),
3139             m_javaGlue->m_updateTextSelection, reinterpret_cast<int>(focusNode),
3140             rtc->selectionStart(), rtc->selectionEnd(), m_textGeneration);
3141     checkException(env);
3142 }
3143
3144 void WebViewCore::updateTextfield(WebCore::Node* ptr, bool changeToPassword,
3145         const WTF::String& text)
3146 {
3147     if (m_blockTextfieldUpdates)
3148         return;
3149     JNIEnv* env = JSC::Bindings::getJNIEnv();
3150     if (changeToPassword) {
3151         env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_updateTextfield,
3152                 (int) ptr, true, 0, m_textGeneration);
3153         checkException(env);
3154         return;
3155     }
3156     jstring string = WtfStringToJstring(env, text);
3157     env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_updateTextfield,
3158             (int) ptr, false, string, m_textGeneration);
3159     env->DeleteLocalRef(string);
3160     checkException(env);
3161 }
3162
3163 void WebViewCore::clearTextEntry()
3164 {
3165     JNIEnv* env = JSC::Bindings::getJNIEnv();
3166     env->CallVoidMethod(m_javaGlue->object(env).get(),
3167         m_javaGlue->m_clearTextEntry);
3168 }
3169
3170 void WebViewCore::setBackgroundColor(SkColor c)
3171 {
3172     WebCore::FrameView* view = m_mainFrame->view();
3173     if (!view)
3174         return;
3175
3176     // need (int) cast to find the right constructor
3177     WebCore::Color bcolor((int)SkColorGetR(c), (int)SkColorGetG(c),
3178                           (int)SkColorGetB(c), (int)SkColorGetA(c));
3179     view->setBaseBackgroundColor(bcolor);
3180
3181     // Background color of 0 indicates we want a transparent background
3182     if (c == 0)
3183         view->setTransparent(true);
3184 }
3185
3186 jclass WebViewCore::getPluginClass(const WTF::String& libName, const char* className)
3187 {
3188     JNIEnv* env = JSC::Bindings::getJNIEnv();
3189
3190     jstring libString = WtfStringToJstring(env, libName);
3191     jstring classString = env->NewStringUTF(className);
3192     jobject pluginClass = env->CallObjectMethod(m_javaGlue->object(env).get(),
3193                                            m_javaGlue->m_getPluginClass,
3194                                            libString, classString);
3195     checkException(env);
3196
3197     // cleanup unneeded local JNI references
3198     env->DeleteLocalRef(libString);
3199     env->DeleteLocalRef(classString);
3200
3201     if (pluginClass != NULL) {
3202         return static_cast<jclass>(pluginClass);
3203     } else {
3204         return NULL;
3205     }
3206 }
3207
3208 void WebViewCore::showFullScreenPlugin(jobject childView, NPP npp)
3209 {
3210     JNIEnv* env = JSC::Bindings::getJNIEnv();
3211     AutoJObject obj = m_javaGlue->object(env);
3212
3213     env->CallVoidMethod(obj.get(),
3214                         m_javaGlue->m_showFullScreenPlugin, childView, (int)npp);
3215     checkException(env);
3216 }
3217
3218 void WebViewCore::hideFullScreenPlugin()
3219 {
3220     JNIEnv* env = JSC::Bindings::getJNIEnv();
3221     env->CallVoidMethod(m_javaGlue->object(env).get(),
3222                         m_javaGlue->m_hideFullScreenPlugin);
3223     checkException(env);
3224 }
3225
3226 jobject WebViewCore::addSurface(jobject view, int x, int y, int width, int height)
3227 {
3228     JNIEnv* env = JSC::Bindings::getJNIEnv();
3229     jobject result = env->CallObjectMethod(m_javaGlue->object(env).get(),
3230                                            m_javaGlue->m_addSurface,
3231                                            view, x, y, width, height);
3232     checkException(env);
3233     return result;
3234 }
3235
3236 void WebViewCore::updateSurface(jobject childView, int x, int y, int width, int height)
3237 {
3238     JNIEnv* env = JSC::Bindings::getJNIEnv();
3239     env->CallVoidMethod(m_javaGlue->object(env).get(),
3240                         m_javaGlue->m_updateSurface, childView,
3241                         x, y, width, height);
3242     checkException(env);
3243 }
3244
3245 void WebViewCore::destroySurface(jobject childView)
3246 {
3247     JNIEnv* env = JSC::Bindings::getJNIEnv();
3248     env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_destroySurface, childView);
3249     checkException(env);
3250 }
3251
3252 jobject WebViewCore::getContext()
3253 {
3254     JNIEnv* env = JSC::Bindings::getJNIEnv();
3255     AutoJObject obj = m_javaGlue->object(env);
3256
3257     jobject result = env->CallObjectMethod(obj.get(), m_javaGlue->m_getContext);
3258     checkException(env);
3259     return result;
3260 }
3261
3262 bool WebViewCore::validNodeAndBounds(Frame* frame, Node* node,
3263     const IntRect& originalAbsoluteBounds)
3264 {
3265     bool valid = CacheBuilder::validNode(m_mainFrame, frame, node);
3266     if (!valid)
3267         return false;
3268     RenderObject* renderer = node->renderer();
3269     if (!renderer)
3270         return false;
3271     IntRect absBounds = node->hasTagName(HTMLNames::areaTag)
3272         ? CacheBuilder::getAreaRect(static_cast<HTMLAreaElement*>(node))
3273         : renderer->absoluteBoundingBoxRect();
3274     return absBounds == originalAbsoluteBounds;
3275 }
3276
3277 void WebViewCore::showRect(int left, int top, int width, int height,
3278         int contentWidth, int contentHeight, float xPercentInDoc,
3279         float xPercentInView, float yPercentInDoc, float yPercentInView)
3280 {
3281     JNIEnv* env = JSC::Bindings::getJNIEnv();
3282     env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_showRect,
3283             left, top, width, height, contentWidth, contentHeight,
3284             xPercentInDoc, xPercentInView, yPercentInDoc, yPercentInView);
3285     checkException(env);
3286 }
3287
3288 void WebViewCore::centerFitRect(int x, int y, int width, int height)
3289 {
3290     JNIEnv* env = JSC::Bindings::getJNIEnv();
3291     env->CallVoidMethod(m_javaGlue->object(env).get(),
3292             m_javaGlue->m_centerFitRect, x, y, width, height);
3293     checkException(env);
3294 }
3295
3296
3297 void WebViewCore::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode verticalMode)
3298 {
3299     JNIEnv* env = JSC::Bindings::getJNIEnv();
3300     env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_setScrollbarModes,
3301             horizontalMode, verticalMode);
3302     checkException(env);
3303 }
3304
3305 void WebViewCore::notifyWebAppCanBeInstalled()
3306 {
3307     JNIEnv* env = JSC::Bindings::getJNIEnv();
3308     env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_setInstallableWebApp);
3309     checkException(env);
3310 }
3311
3312 void WebViewCore::setWebTextViewAutoFillable(int queryId, const string16& previewSummary)
3313 {
3314     JNIEnv* env = JSC::Bindings::getJNIEnv();
3315     jstring preview = env->NewString(previewSummary.data(), previewSummary.length());
3316     env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_setWebTextViewAutoFillable, queryId, preview);
3317     env->DeleteLocalRef(preview);
3318 }
3319
3320 bool WebViewCore::drawIsPaused() const
3321 {
3322     JNIEnv* env = JSC::Bindings::getJNIEnv();
3323     return env->GetBooleanField(m_javaGlue->object(env).get(),
3324         gWebViewCoreFields.m_drawIsPaused);
3325 }
3326
3327 //----------------------------------------------------------------------
3328 // Native JNI methods
3329 //----------------------------------------------------------------------
3330 static void RevealSelection(JNIEnv *env, jobject obj)
3331 {
3332     GET_NATIVE_VIEW(env, obj)->revealSelection();
3333 }
3334
3335 static jstring RequestLabel(JNIEnv *env, jobject obj, int framePointer,
3336         int nodePointer)
3337 {
3338     return WtfStringToJstring(env, GET_NATIVE_VIEW(env, obj)->requestLabel(
3339             (WebCore::Frame*) framePointer, (WebCore::Node*) nodePointer));
3340 }
3341
3342 static void ClearContent(JNIEnv *env, jobject obj)
3343 {
3344 #ifdef ANDROID_INSTRUMENT
3345     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3346 #endif
3347     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3348     viewImpl->clearContent();
3349 }
3350
3351 static void UpdateFrameCacheIfLoading(JNIEnv *env, jobject obj)
3352 {
3353     GET_NATIVE_VIEW(env, obj)->updateFrameCacheIfLoading();
3354 }
3355
3356 static void SetSize(JNIEnv *env, jobject obj, jint width, jint height,
3357         jint textWrapWidth, jfloat scale, jint screenWidth, jint screenHeight,
3358         jint anchorX, jint anchorY, jboolean ignoreHeight)
3359 {
3360 #ifdef ANDROID_INSTRUMENT
3361     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3362 #endif
3363     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3364     LOGV("webviewcore::nativeSetSize(%u %u)\n viewImpl: %p", (unsigned)width, (unsigned)height, viewImpl);
3365     LOG_ASSERT(viewImpl, "viewImpl not set in nativeSetSize");
3366     viewImpl->setSizeScreenWidthAndScale(width, height, textWrapWidth, scale,
3367             screenWidth, screenHeight, anchorX, anchorY, ignoreHeight);
3368 }
3369
3370 static void SetScrollOffset(JNIEnv *env, jobject obj, jint gen, jint userScrolled, jint x, jint y)
3371 {
3372 #ifdef ANDROID_INSTRUMENT
3373     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3374 #endif
3375     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3376     LOG_ASSERT(viewImpl, "need viewImpl");
3377
3378     viewImpl->setScrollOffset(gen, userScrolled, x, y);
3379 }
3380
3381 static void SetGlobalBounds(JNIEnv *env, jobject obj, jint x, jint y, jint h,
3382                             jint v)
3383 {
3384 #ifdef ANDROID_INSTRUMENT
3385     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3386 #endif
3387     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3388     LOG_ASSERT(viewImpl, "need viewImpl");
3389
3390     viewImpl->setGlobalBounds(x, y, h, v);
3391 }
3392
3393 static jboolean Key(JNIEnv *env, jobject obj, jint keyCode, jint unichar,
3394         jint repeatCount, jboolean isShift, jboolean isAlt, jboolean isSym,
3395         jboolean isDown)
3396 {
3397 #ifdef ANDROID_INSTRUMENT
3398     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3399 #endif
3400     return GET_NATIVE_VIEW(env, obj)->key(PlatformKeyboardEvent(keyCode,
3401         unichar, repeatCount, isDown, isShift, isAlt, isSym));
3402 }
3403
3404 static void Click(JNIEnv *env, jobject obj, int framePtr, int nodePtr)
3405 {
3406 #ifdef ANDROID_INSTRUMENT
3407     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3408 #endif
3409     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3410     LOG_ASSERT(viewImpl, "viewImpl not set in Click");
3411
3412     viewImpl->click(reinterpret_cast<WebCore::Frame*>(framePtr),
3413         reinterpret_cast<WebCore::Node*>(nodePtr));
3414 }
3415
3416 static void ContentInvalidateAll(JNIEnv *env, jobject obj)
3417 {
3418     GET_NATIVE_VIEW(env, obj)->contentInvalidateAll();
3419 }
3420
3421 static void DeleteSelection(JNIEnv *env, jobject obj, jint start, jint end,
3422         jint textGeneration)
3423 {
3424 #ifdef ANDROID_INSTRUMENT
3425     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3426 #endif
3427     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3428     viewImpl->deleteSelection(start, end, textGeneration);
3429 }
3430
3431 static void SetSelection(JNIEnv *env, jobject obj, jint start, jint end)
3432 {
3433 #ifdef ANDROID_INSTRUMENT
3434     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3435 #endif
3436     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3437     viewImpl->setSelection(start, end);
3438 }
3439
3440 static jstring ModifySelection(JNIEnv *env, jobject obj, jint direction, jint granularity)
3441 {
3442 #ifdef ANDROID_INSTRUMENT
3443     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3444 #endif
3445     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3446     String selectionString = viewImpl->modifySelection(direction, granularity);
3447     return WtfStringToJstring(env, selectionString);
3448 }
3449
3450 static void ReplaceTextfieldText(JNIEnv *env, jobject obj,
3451     jint oldStart, jint oldEnd, jstring replace, jint start, jint end,
3452     jint textGeneration)
3453 {
3454 #ifdef ANDROID_INSTRUMENT
3455     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3456 #endif
3457     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3458     WTF::String webcoreString = jstringToWtfString(env, replace);
3459     viewImpl->replaceTextfieldText(oldStart,
3460             oldEnd, webcoreString, start, end, textGeneration);
3461 }
3462
3463 static void PassToJs(JNIEnv *env, jobject obj,
3464     jint generation, jstring currentText, jint keyCode,
3465     jint keyValue, jboolean down, jboolean cap, jboolean fn, jboolean sym)
3466 {
3467 #ifdef ANDROID_INSTRUMENT
3468     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3469 #endif
3470     WTF::String current = jstringToWtfString(env, currentText);
3471     GET_NATIVE_VIEW(env, obj)->passToJs(generation, current,
3472         PlatformKeyboardEvent(keyCode, keyValue, 0, down, cap, fn, sym));
3473 }
3474
3475 static void ScrollFocusedTextInput(JNIEnv *env, jobject obj, jfloat xPercent,
3476     jint y)
3477 {
3478 #ifdef ANDROID_INSTRUMENT
3479     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3480 #endif
3481     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3482     viewImpl->scrollFocusedTextInput(xPercent, y);
3483 }
3484
3485 static void SetFocusControllerActive(JNIEnv *env, jobject obj, jboolean active)
3486 {
3487 #ifdef ANDROID_INSTRUMENT
3488     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3489 #endif
3490     LOGV("webviewcore::nativeSetFocusControllerActive()\n");
3491     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3492     LOG_ASSERT(viewImpl, "viewImpl not set in nativeSetFocusControllerActive");
3493     viewImpl->setFocusControllerActive(active);
3494 }
3495
3496 static void SaveDocumentState(JNIEnv *env, jobject obj, jint frame)
3497 {
3498 #ifdef ANDROID_INSTRUMENT
3499     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3500 #endif
3501     LOGV("webviewcore::nativeSaveDocumentState()\n");
3502     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3503     LOG_ASSERT(viewImpl, "viewImpl not set in nativeSaveDocumentState");
3504     viewImpl->saveDocumentState((WebCore::Frame*) frame);
3505 }
3506
3507 void WebViewCore::addVisitedLink(const UChar* string, int length)
3508 {
3509     if (m_groupForVisitedLinks)
3510         m_groupForVisitedLinks->addVisitedLink(string, length);
3511 }
3512
3513 static jint UpdateLayers(JNIEnv *env, jobject obj)
3514 {
3515     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3516     BaseLayerAndroid* result = viewImpl->createBaseLayer();
3517     return reinterpret_cast<jint>(result);
3518 }
3519
3520 static jint RecordContent(JNIEnv *env, jobject obj, jobject region, jobject pt)
3521 {
3522 #ifdef ANDROID_INSTRUMENT
3523     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3524 #endif
3525     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3526     SkRegion* nativeRegion = GraphicsJNI::getNativeRegion(env, region);
3527     SkIPoint nativePt;
3528     BaseLayerAndroid* result = viewImpl->recordContent(nativeRegion, &nativePt);
3529     GraphicsJNI::ipoint_to_jpoint(nativePt, env, pt);
3530     return reinterpret_cast<jint>(result);
3531 }
3532
3533 static void SplitContent(JNIEnv *env, jobject obj, jint content)
3534 {
3535 #ifdef ANDROID_INSTRUMENT
3536     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3537 #endif
3538     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3539     viewImpl->splitContent(reinterpret_cast<PictureSet*>(content));
3540 }
3541
3542 static void SendListBoxChoice(JNIEnv* env, jobject obj, jint choice)
3543 {
3544 #ifdef ANDROID_INSTRUMENT
3545     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3546 #endif
3547     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3548     LOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoice");
3549     viewImpl->popupReply(choice);
3550 }
3551
3552 // Set aside a predetermined amount of space in which to place the listbox
3553 // choices, to avoid unnecessary allocations.
3554 // The size here is arbitrary.  We want the size to be at least as great as the
3555 // number of items in the average multiple-select listbox.
3556 #define PREPARED_LISTBOX_STORAGE 10
3557
3558 static void SendListBoxChoices(JNIEnv* env, jobject obj, jbooleanArray jArray,
3559         jint size)
3560 {
3561 #ifdef ANDROID_INSTRUMENT
3562     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3563 #endif
3564     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3565     LOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoices");
3566     jboolean* ptrArray = env->GetBooleanArrayElements(jArray, 0);
3567     SkAutoSTMalloc<PREPARED_LISTBOX_STORAGE, int> storage(size);
3568     int* array = storage.get();
3569     int count = 0;
3570     for (int i = 0; i < size; i++) {
3571         if (ptrArray[i]) {
3572             array[count++] = i;
3573         }
3574     }
3575     env->ReleaseBooleanArrayElements(jArray, ptrArray, JNI_ABORT);
3576     viewImpl->popupReply(array, count);
3577 }
3578
3579 static jstring FindAddress(JNIEnv *env, jobject obj, jstring addr,
3580     jboolean caseInsensitive)
3581 {
3582 #ifdef ANDROID_INSTRUMENT
3583     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3584 #endif
3585     if (!addr)
3586         return 0;
3587     int length = env->GetStringLength(addr);
3588     if (!length)
3589         return 0;
3590     const jchar* addrChars = env->GetStringChars(addr, 0);
3591     int start, end;
3592     bool success = CacheBuilder::FindAddress(addrChars, length,
3593         &start, &end, caseInsensitive) == CacheBuilder::FOUND_COMPLETE;
3594     jstring ret = 0;
3595     if (success) {
3596         ret = env->NewString(addrChars + start, end - start);
3597         env->DeleteLocalRef(ret);
3598     }
3599     env->ReleaseStringChars(addr, addrChars);
3600     return ret;
3601 }
3602
3603 static jboolean HandleTouchEvent(JNIEnv *env, jobject obj, jint action,
3604                                  jintArray xArray, jintArray yArray, jint count, jint metaState)
3605 {
3606 #ifdef ANDROID_INSTRUMENT
3607     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3608 #endif
3609     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3610     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
3611     jint* ptrXArray = env->GetIntArrayElements(xArray, 0);
3612     jint* ptrYArray = env->GetIntArrayElements(yArray, 0);
3613     Vector<IntPoint> points(count);
3614     for (int c = 0; c < count; c++) {
3615         points[c].setX(ptrXArray[c]);
3616         points[c].setY(ptrYArray[c]);
3617     }
3618     env->ReleaseIntArrayElements(xArray, ptrXArray, JNI_ABORT);
3619     env->ReleaseIntArrayElements(yArray, ptrYArray, JNI_ABORT);
3620
3621     return viewImpl->handleTouchEvent(action, points, metaState);
3622 }
3623
3624 static void TouchUp(JNIEnv *env, jobject obj, jint touchGeneration,
3625         jint frame, jint node, jint x, jint y)
3626 {
3627 #ifdef ANDROID_INSTRUMENT
3628     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3629 #endif
3630     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3631     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
3632     viewImpl->touchUp(touchGeneration,
3633         (WebCore::Frame*) frame, (WebCore::Node*) node, x, y);
3634 }
3635
3636 static jstring RetrieveHref(JNIEnv *env, jobject obj, jint frame,
3637         jint node)
3638 {
3639 #ifdef ANDROID_INSTRUMENT
3640     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3641 #endif
3642     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3643     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
3644     WTF::String result = viewImpl->retrieveHref((WebCore::Frame*) frame,
3645             (WebCore::Node*) node);
3646     if (!result.isEmpty())
3647         return WtfStringToJstring(env, result);
3648     return 0;
3649 }
3650
3651 static jstring RetrieveAnchorText(JNIEnv *env, jobject obj, jint frame,
3652         jint node)
3653 {
3654 #ifdef ANDROID_INSTRUMENT
3655     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3656 #endif
3657     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3658     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
3659     WTF::String result = viewImpl->retrieveAnchorText((WebCore::Frame*) frame,
3660             (WebCore::Node*) node);
3661     if (!result.isEmpty())
3662         return WtfStringToJstring(env, result);
3663     return 0;
3664 }
3665
3666
3667 static void MoveFocus(JNIEnv *env, jobject obj, jint framePtr, jint nodePtr)
3668 {
3669 #ifdef ANDROID_INSTRUMENT
3670     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3671 #endif
3672     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3673     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
3674     viewImpl->moveFocus((WebCore::Frame*) framePtr, (WebCore::Node*) nodePtr);
3675 }
3676
3677 static void MoveMouse(JNIEnv *env, jobject obj, jint frame,
3678         jint x, jint y)
3679 {
3680 #ifdef ANDROID_INSTRUMENT
3681     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3682 #endif
3683     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3684     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
3685     viewImpl->moveMouse((WebCore::Frame*) frame, x, y);
3686 }
3687
3688 static void MoveMouseIfLatest(JNIEnv *env, jobject obj, jint moveGeneration,
3689         jint frame, jint x, jint y)
3690 {
3691 #ifdef ANDROID_INSTRUMENT
3692     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3693 #endif
3694     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3695     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
3696     viewImpl->moveMouseIfLatest(moveGeneration,
3697         (WebCore::Frame*) frame, x, y);
3698 }
3699
3700 static void UpdateFrameCache(JNIEnv *env, jobject obj)
3701 {
3702 #ifdef ANDROID_INSTRUMENT
3703     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3704 #endif
3705     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3706     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
3707     viewImpl->updateFrameCache();
3708 }
3709
3710 static jint GetContentMinPrefWidth(JNIEnv *env, jobject obj)
3711 {
3712 #ifdef ANDROID_INSTRUMENT
3713     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3714 #endif
3715     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3716     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
3717
3718     WebCore::Frame* frame = viewImpl->mainFrame();
3719     if (frame) {
3720         WebCore::Document* document = frame->document();
3721         if (document) {
3722             WebCore::RenderObject* renderer = document->renderer();
3723             if (renderer && renderer->isRenderView()) {
3724                 return renderer->minPreferredLogicalWidth();
3725             }
3726         }
3727     }
3728     return 0;
3729 }
3730
3731 static void SetViewportSettingsFromNative(JNIEnv *env, jobject obj)
3732 {
3733 #ifdef ANDROID_INSTRUMENT
3734     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3735 #endif
3736     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3737     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
3738
3739     WebCore::Settings* s = viewImpl->mainFrame()->page()->settings();
3740     if (!s)
3741         return;
3742
3743 #ifdef ANDROID_META_SUPPORT
3744     env->SetIntField(obj, gWebViewCoreFields.m_viewportWidth, s->viewportWidth());
3745     env->SetIntField(obj, gWebViewCoreFields.m_viewportHeight, s->viewportHeight());
3746     env->SetIntField(obj, gWebViewCoreFields.m_viewportInitialScale, s->viewportInitialScale());
3747     env->SetIntField(obj, gWebViewCoreFields.m_viewportMinimumScale, s->viewportMinimumScale());
3748     env->SetIntField(obj, gWebViewCoreFields.m_viewportMaximumScale, s->viewportMaximumScale());
3749     env->SetBooleanField(obj, gWebViewCoreFields.m_viewportUserScalable, s->viewportUserScalable());
3750     env->SetIntField(obj, gWebViewCoreFields.m_viewportDensityDpi, s->viewportTargetDensityDpi());
3751 #endif
3752 }
3753
3754 static void SetBackgroundColor(JNIEnv *env, jobject obj, jint color)
3755 {
3756 #ifdef ANDROID_INSTRUMENT
3757     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3758 #endif
3759     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3760     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
3761
3762     viewImpl->setBackgroundColor((SkColor) color);
3763 }
3764
3765 static void DumpDomTree(JNIEnv *env, jobject obj, jboolean useFile)
3766 {
3767     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3768     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
3769
3770     viewImpl->dumpDomTree(useFile);
3771 }
3772
3773 static void DumpRenderTree(JNIEnv *env, jobject obj, jboolean useFile)
3774 {
3775     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3776     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
3777
3778     viewImpl->dumpRenderTree(useFile);
3779 }
3780
3781 static void DumpNavTree(JNIEnv *env, jobject obj)
3782 {
3783     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3784     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
3785
3786     viewImpl->dumpNavTree();
3787 }
3788
3789 static void DumpV8Counters(JNIEnv*, jobject)
3790 {
3791 #if USE(V8)
3792 #ifdef ANDROID_INSTRUMENT
3793     V8Counters::dumpCounters();
3794 #endif
3795 #endif
3796 }
3797
3798 static void SetJsFlags(JNIEnv *env, jobject obj, jstring flags)
3799 {
3800 #if USE(V8)
3801     WTF::String flagsString = jstringToWtfString(env, flags);
3802     WTF::CString utf8String = flagsString.utf8();
3803     WebCore::ScriptController::setFlags(utf8String.data(), utf8String.length());
3804 #endif
3805 }
3806
3807
3808 // Called from the Java side to set a new quota for the origin or new appcache
3809 // max size in response to a notification that the original quota was exceeded or
3810 // that the appcache has reached its maximum size.
3811 static void SetNewStorageLimit(JNIEnv* env, jobject obj, jlong quota) {
3812 #if ENABLE(DATABASE) || ENABLE(OFFLINE_WEB_APPLICATIONS)
3813     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3814     Frame* frame = viewImpl->mainFrame();
3815
3816     // The main thread is blocked awaiting this response, so now we can wake it
3817     // up.
3818     ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client());
3819     chromeC->wakeUpMainThreadWithNewQuota(quota);
3820 #endif
3821 }
3822
3823 // Called from Java to provide a Geolocation permission state for the specified origin.
3824 static void GeolocationPermissionsProvide(JNIEnv* env, jobject obj, jstring origin, jboolean allow, jboolean remember) {
3825     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3826     Frame* frame = viewImpl->mainFrame();
3827
3828     ChromeClientAndroid* chromeClient = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client());
3829     chromeClient->provideGeolocationPermissions(jstringToWtfString(env, origin), allow, remember);
3830 }
3831
3832 static void RegisterURLSchemeAsLocal(JNIEnv* env, jobject obj, jstring scheme) {
3833 #ifdef ANDROID_INSTRUMENT
3834     TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3835 #endif
3836     WebCore::SchemeRegistry::registerURLSchemeAsLocal(jstringToWtfString(env, scheme));
3837 }
3838
3839 static bool FocusBoundsChanged(JNIEnv* env, jobject obj)
3840 {
3841     return GET_NATIVE_VIEW(env, obj)->focusBoundsChanged();
3842 }
3843
3844 static void Pause(JNIEnv* env, jobject obj)
3845 {
3846     // This is called for the foreground tab when the browser is put to the
3847     // background (and also for any tab when it is put to the background of the
3848     // browser). The browser can only be killed by the system when it is in the
3849     // background, so saving the Geolocation permission state now ensures that
3850     // is maintained when the browser is killed.
3851     ChromeClient* chromeClient = GET_NATIVE_VIEW(env, obj)->mainFrame()->page()->chrome()->client();
3852     ChromeClientAndroid* chromeClientAndroid = static_cast<ChromeClientAndroid*>(chromeClient);
3853     chromeClientAndroid->storeGeolocationPermissions();
3854
3855     Frame* mainFrame = GET_NATIVE_VIEW(env, obj)->mainFrame();
3856     for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) {
3857         Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation();
3858         if (geolocation)
3859             geolocation->suspend();
3860     }
3861
3862     GET_NATIVE_VIEW(env, obj)->deviceMotionAndOrientationManager()->maybeSuspendClients();
3863
3864     ANPEvent event;
3865     SkANP::InitEvent(&event, kLifecycle_ANPEventType);
3866     event.data.lifecycle.action = kPause_ANPLifecycleAction;
3867     GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event);
3868
3869     GET_NATIVE_VIEW(env, obj)->setIsPaused(true);
3870 }
3871
3872 static void Resume(JNIEnv* env, jobject obj)
3873 {
3874     Frame* mainFrame = GET_NATIVE_VIEW(env, obj)->mainFrame();
3875     for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) {
3876         Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation();
3877         if (geolocation)
3878             geolocation->resume();
3879     }
3880
3881     GET_NATIVE_VIEW(env, obj)->deviceMotionAndOrientationManager()->maybeResumeClients();
3882
3883     ANPEvent event;
3884     SkANP::InitEvent(&event, kLifecycle_ANPEventType);
3885     event.data.lifecycle.action = kResume_ANPLifecycleAction;
3886     GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event);
3887
3888     GET_NATIVE_VIEW(env, obj)->setIsPaused(false);
3889 }
3890
3891 static void FreeMemory(JNIEnv* env, jobject obj)
3892 {
3893     ANPEvent event;
3894     SkANP::InitEvent(&event, kLifecycle_ANPEventType);
3895     event.data.lifecycle.action = kFreeMemory_ANPLifecycleAction;
3896     GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event);
3897 }
3898
3899 static void ProvideVisitedHistory(JNIEnv *env, jobject obj, jobject hist)
3900 {
3901     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3902     LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
3903
3904     jobjectArray array = static_cast<jobjectArray>(hist);
3905
3906     jsize len = env->GetArrayLength(array);
3907     for (jsize i = 0; i < len; i++) {
3908         jstring item = static_cast<jstring>(env->GetObjectArrayElement(array, i));
3909         const UChar* str = static_cast<const UChar*>(env->GetStringChars(item, NULL));
3910         jsize len = env->GetStringLength(item);
3911         viewImpl->addVisitedLink(str, len);
3912         env->ReleaseStringChars(item, str);
3913         env->DeleteLocalRef(item);
3914     }
3915 }
3916
3917 // Notification from the UI thread that the plugin's full-screen surface has been discarded
3918 static void FullScreenPluginHidden(JNIEnv* env, jobject obj, jint npp)
3919 {
3920     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3921     PluginWidgetAndroid* plugin = viewImpl->getPluginWidget((NPP)npp);
3922     if (plugin)
3923         plugin->exitFullScreen(false);
3924 }
3925
3926 static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj)
3927 {
3928     int L, T, R, B;
3929     GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B);
3930     return WebCore::IntRect(L, T, R - L, B - T);
3931 }
3932
3933 static bool ValidNodeAndBounds(JNIEnv *env, jobject obj, int frame, int node,
3934     jobject rect)
3935 {
3936     IntRect nativeRect = jrect_to_webrect(env, rect);
3937     return GET_NATIVE_VIEW(env, obj)->validNodeAndBounds(
3938             reinterpret_cast<Frame*>(frame),
3939             reinterpret_cast<Node*>(node), nativeRect);
3940 }
3941
3942 static jobject GetTouchHighlightRects(JNIEnv* env, jobject obj, jint x, jint y, jint slop)
3943 {
3944     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3945     if (!viewImpl)
3946         return NULL;
3947     Vector<IntRect> rects = viewImpl->getTouchHighlightRects(x, y, slop);
3948     if (rects.isEmpty())
3949         return NULL;
3950
3951     jclass arrayClass = env->FindClass("java/util/ArrayList");
3952     LOG_ASSERT(arrayClass, "Could not find java/util/ArrayList");
3953     jmethodID init = env->GetMethodID(arrayClass, "<init>", "(I)V");
3954     LOG_ASSERT(init, "Could not find constructor for ArrayList");
3955     jobject array = env->NewObject(arrayClass, init, rects.size());
3956     LOG_ASSERT(array, "Could not create a new ArrayList");
3957     jmethodID add = env->GetMethodID(arrayClass, "add", "(Ljava/lang/Object;)Z");
3958     LOG_ASSERT(add, "Could not find add method on ArrayList");
3959     jclass rectClass = env->FindClass("android/graphics/Rect");
3960     LOG_ASSERT(rectClass, "Could not find android/graphics/Rect");
3961     jmethodID rectinit = env->GetMethodID(rectClass, "<init>", "(IIII)V");
3962     LOG_ASSERT(rectinit, "Could not find init method on Rect");
3963
3964     for (size_t i = 0; i < rects.size(); i++) {
3965         jobject rect = env->NewObject(rectClass, rectinit, rects[i].x(),
3966                 rects[i].y(), rects[i].right(), rects[i].bottom());
3967         if (rect) {
3968             env->CallBooleanMethod(array, add, rect);
3969             env->DeleteLocalRef(rect);
3970         }
3971     }
3972
3973     env->DeleteLocalRef(rectClass);
3974     env->DeleteLocalRef(arrayClass);
3975     return array;
3976 }
3977
3978 static void AutoFillForm(JNIEnv* env, jobject obj, jint queryId)
3979 {
3980 #if ENABLE(WEB_AUTOFILL)
3981     WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3982     if (!viewImpl)
3983         return;
3984
3985     WebCore::Frame* frame = viewImpl->mainFrame();
3986     if (frame) {
3987         EditorClientAndroid* editorC = static_cast<EditorClientAndroid*>(frame->page()->editorClient());
3988         WebAutoFill* autoFill = editorC->getAutoFill();
3989         autoFill->fillFormFields(queryId);
3990     }
3991 #endif
3992 }
3993
3994 // ----------------------------------------------------------------------------
3995
3996 /*
3997  * JNI registration.
3998  */
3999 static JNINativeMethod gJavaWebViewCoreMethods[] = {
4000     { "nativeClearContent", "()V",
4001             (void*) ClearContent },
4002     { "nativeFocusBoundsChanged", "()Z",
4003         (void*) FocusBoundsChanged } ,
4004     { "nativeKey", "(IIIZZZZ)Z",
4005         (void*) Key },
4006     { "nativeClick", "(II)V",
4007         (void*) Click },
4008     { "nativeContentInvalidateAll", "()V",
4009         (void*) ContentInvalidateAll },
4010     { "nativeSendListBoxChoices", "([ZI)V",
4011         (void*) SendListBoxChoices },
4012     { "nativeSendListBoxChoice", "(I)V",
4013         (void*) SendListBoxChoice },
4014     { "nativeSetSize", "(IIIFIIIIZ)V",
4015         (void*) SetSize },
4016     { "nativeSetScrollOffset", "(IIII)V",
4017         (void*) SetScrollOffset },
4018     { "nativeSetGlobalBounds", "(IIII)V",
4019         (void*) SetGlobalBounds },
4020     { "nativeSetSelection", "(II)V",
4021         (void*) SetSelection } ,
4022     { "nativeModifySelection", "(II)Ljava/lang/String;",
4023         (void*) ModifySelection },
4024     { "nativeDeleteSelection", "(III)V",
4025         (void*) DeleteSelection } ,
4026     { "nativeReplaceTextfieldText", "(IILjava/lang/String;III)V",
4027         (void*) ReplaceTextfieldText } ,
4028     { "nativeMoveFocus", "(II)V",
4029         (void*) MoveFocus },
4030     { "nativeMoveMouse", "(III)V",
4031         (void*) MoveMouse },
4032     { "nativeMoveMouseIfLatest", "(IIII)V",
4033         (void*) MoveMouseIfLatest },
4034     { "passToJs", "(ILjava/lang/String;IIZZZZ)V",
4035         (void*) PassToJs },
4036     { "nativeScrollFocusedTextInput", "(FI)V",
4037         (void*) ScrollFocusedTextInput },
4038     { "nativeSetFocusControllerActive", "(Z)V",
4039         (void*) SetFocusControllerActive },
4040     { "nativeSaveDocumentState", "(I)V",
4041         (void*) SaveDocumentState },
4042     { "nativeFindAddress", "(Ljava/lang/String;Z)Ljava/lang/String;",
4043         (void*) FindAddress },
4044     { "nativeHandleTouchEvent", "(I[I[III)Z",
4045             (void*) HandleTouchEvent },
4046     { "nativeTouchUp", "(IIIII)V",
4047         (void*) TouchUp },
4048     { "nativeRetrieveHref", "(II)Ljava/lang/String;",
4049         (void*) RetrieveHref },
4050     { "nativeRetrieveAnchorText", "(II)Ljava/lang/String;",
4051         (void*) RetrieveAnchorText },
4052     { "nativeUpdateFrameCache", "()V",
4053         (void*) UpdateFrameCache },
4054     { "nativeGetContentMinPrefWidth", "()I",
4055         (void*) GetContentMinPrefWidth },
4056     { "nativeUpdateLayers", "()I",
4057         (void*) UpdateLayers },
4058     { "nativeRecordContent", "(Landroid/graphics/Region;Landroid/graphics/Point;)I",
4059         (void*) RecordContent },
4060     { "setViewportSettingsFromNative", "()V",
4061         (void*) SetViewportSettingsFromNative },
4062     { "nativeSplitContent", "(I)V",
4063         (void*) SplitContent },
4064     { "nativeSetBackgroundColor", "(I)V",
4065         (void*) SetBackgroundColor },
4066     { "nativeRegisterURLSchemeAsLocal", "(Ljava/lang/String;)V",
4067         (void*) RegisterURLSchemeAsLocal },
4068     { "nativeDumpDomTree", "(Z)V",
4069         (void*) DumpDomTree },
4070     { "nativeDumpRenderTree", "(Z)V",
4071         (void*) DumpRenderTree },
4072     { "nativeDumpNavTree", "()V",
4073         (void*) DumpNavTree },
4074     { "nativeDumpV8Counters", "()V",
4075         (void*) DumpV8Counters },
4076     { "nativeSetNewStorageLimit", "(J)V",
4077         (void*) SetNewStorageLimit },
4078     { "nativeGeolocationPermissionsProvide", "(Ljava/lang/String;ZZ)V",
4079         (void*) GeolocationPermissionsProvide },
4080     { "nativePause", "()V", (void*) Pause },
4081     { "nativeResume", "()V", (void*) Resume },
4082     { "nativeFreeMemory", "()V", (void*) FreeMemory },
4083     { "nativeSetJsFlags", "(Ljava/lang/String;)V", (void*) SetJsFlags },
4084     { "nativeRequestLabel", "(II)Ljava/lang/String;",
4085         (void*) RequestLabel },
4086     { "nativeRevealSelection", "()V", (void*) RevealSelection },
4087     { "nativeUpdateFrameCacheIfLoading", "()V",
4088         (void*) UpdateFrameCacheIfLoading },
4089     { "nativeProvideVisitedHistory", "([Ljava/lang/String;)V",
4090         (void*) ProvideVisitedHistory },
4091     { "nativeFullScreenPluginHidden", "(I)V",
4092         (void*) FullScreenPluginHidden },
4093     { "nativeValidNodeAndBounds", "(IILandroid/graphics/Rect;)Z",
4094         (void*) ValidNodeAndBounds },
4095     { "nativeGetTouchHighlightRects", "(III)Ljava/util/ArrayList;",
4096         (void*) GetTouchHighlightRects },
4097     { "nativeAutoFillForm", "(I)V",
4098         (void*) AutoFillForm },
4099 };
4100
4101 int registerWebViewCore(JNIEnv* env)
4102 {
4103     jclass widget = env->FindClass("android/webkit/WebViewCore");
4104     LOG_ASSERT(widget,
4105             "Unable to find class android/webkit/WebViewCore");
4106     gWebViewCoreFields.m_nativeClass = env->GetFieldID(widget, "mNativeClass",
4107             "I");
4108     LOG_ASSERT(gWebViewCoreFields.m_nativeClass,
4109             "Unable to find android/webkit/WebViewCore.mNativeClass");
4110     gWebViewCoreFields.m_viewportWidth = env->GetFieldID(widget,
4111             "mViewportWidth", "I");
4112     LOG_ASSERT(gWebViewCoreFields.m_viewportWidth,
4113             "Unable to find android/webkit/WebViewCore.mViewportWidth");
4114     gWebViewCoreFields.m_viewportHeight = env->GetFieldID(widget,
4115             "mViewportHeight", "I");
4116     LOG_ASSERT(gWebViewCoreFields.m_viewportHeight,
4117             "Unable to find android/webkit/WebViewCore.mViewportHeight");
4118     gWebViewCoreFields.m_viewportInitialScale = env->GetFieldID(widget,
4119             "mViewportInitialScale", "I");
4120     LOG_ASSERT(gWebViewCoreFields.m_viewportInitialScale,
4121             "Unable to find android/webkit/WebViewCore.mViewportInitialScale");
4122     gWebViewCoreFields.m_viewportMinimumScale = env->GetFieldID(widget,
4123             "mViewportMinimumScale", "I");
4124     LOG_ASSERT(gWebViewCoreFields.m_viewportMinimumScale,
4125             "Unable to find android/webkit/WebViewCore.mViewportMinimumScale");
4126     gWebViewCoreFields.m_viewportMaximumScale = env->GetFieldID(widget,
4127             "mViewportMaximumScale", "I");
4128     LOG_ASSERT(gWebViewCoreFields.m_viewportMaximumScale,
4129             "Unable to find android/webkit/WebViewCore.mViewportMaximumScale");
4130     gWebViewCoreFields.m_viewportUserScalable = env->GetFieldID(widget,
4131             "mViewportUserScalable", "Z");
4132     LOG_ASSERT(gWebViewCoreFields.m_viewportUserScalable,
4133             "Unable to find android/webkit/WebViewCore.mViewportUserScalable");
4134     gWebViewCoreFields.m_viewportDensityDpi = env->GetFieldID(widget,
4135             "mViewportDensityDpi", "I");
4136     LOG_ASSERT(gWebViewCoreFields.m_viewportDensityDpi,
4137             "Unable to find android/webkit/WebViewCore.mViewportDensityDpi");
4138     gWebViewCoreFields.m_webView = env->GetFieldID(widget,
4139             "mWebView", "Landroid/webkit/WebView;");
4140     LOG_ASSERT(gWebViewCoreFields.m_webView,
4141             "Unable to find android/webkit/WebViewCore.mWebView");
4142     gWebViewCoreFields.m_drawIsPaused = env->GetFieldID(widget,
4143             "mDrawIsPaused", "Z");
4144     LOG_ASSERT(gWebViewCoreFields.m_drawIsPaused,
4145             "Unable to find android/webkit/WebViewCore.mDrawIsPaused");
4146
4147     gWebViewCoreStaticMethods.m_isSupportedMediaMimeType =
4148         env->GetStaticMethodID(widget, "isSupportedMediaMimeType", "(Ljava/lang/String;)Z");
4149     LOG_FATAL_IF(gWebViewCoreStaticMethods.m_isSupportedMediaMimeType == NULL,
4150         "Could not find static method isSupportedMediaMimeType from WebViewCore");
4151
4152     env->DeleteLocalRef(widget);
4153
4154     return jniRegisterNativeMethods(env, "android/webkit/WebViewCore",
4155             gJavaWebViewCoreMethods, NELEM(gJavaWebViewCoreMethods));
4156 }
4157
4158 } /* namespace android */