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