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