OSDN Git Service

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