OSDN Git Service

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