OSDN Git Service

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