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