2 * Copyright 2006, The Android Open Source Project
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
26 #define LOG_TAG "webcoreglue"
29 #include "WebViewCore.h"
31 #include "AccessibilityObject.h"
32 #include "Attribute.h"
33 #include "BaseLayerAndroid.h"
34 #include "CachedNode.h"
35 #include "CachedRoot.h"
37 #include "ChromeClientAndroid.h"
38 #include "ChromiumIncludes.h"
39 #include "ClientRect.h"
40 #include "ClientRectList.h"
42 #include "CSSPropertyNames.h"
43 #include "CSSValueKeywords.h"
44 #include "DatabaseTracker.h"
46 #include "DOMWindow.h"
47 #include "DOMSelection.h"
50 #include "EditorClientAndroid.h"
51 #include "EventHandler.h"
52 #include "EventNames.h"
53 #include "ExceptionCode.h"
54 #include "FocusController.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"
87 #include "PageGroup.h"
88 #include "PlatformKeyboardEvent.h"
89 #include "PlatformString.h"
90 #include "PluginWidgetAndroid.h"
91 #include "PluginView.h"
93 #include "ProgressTracker.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 "RuntimeEnabledFeatures.h"
105 #include "SchemeRegistry.h"
106 #include "SelectionController.h"
107 #include "Settings.h"
109 #include "SkTemplates.h"
110 #include "SkTDArray.h"
112 #include "SkCanvas.h"
113 #include "SkPicture.h"
116 #include "TypingCommand.h"
117 #include "WebCache.h"
118 #include "WebCoreFrameBridge.h"
119 #include "WebFrameView.h"
120 #include "WindowsKeyboardCodes.h"
121 #include "android_graphics.h"
122 #include "autofill/WebAutofill.h"
123 #include "htmlediting.h"
127 #include <JNIUtility.h>
128 #include <ui/KeycodeLabels.h>
129 #include <wtf/CurrentTime.h>
130 #include <wtf/text/AtomicString.h>
131 #include <wtf/text/StringImpl.h>
134 #include "ScriptController.h"
135 #include "V8Counters.h"
136 #include <wtf/text/CString.h>
143 #if ENABLE(TOUCH_EVENTS) // Android
144 #include "PlatformTouchEvent.h"
147 #ifdef ANDROID_DOM_LOGGING
148 #include "AndroidLog.h"
149 #include "RenderTreeAsText.h"
150 #include <wtf/text/CString.h>
152 FILE* gDomTreeFile = 0;
153 FILE* gRenderTreeFile = 0;
156 #ifdef ANDROID_INSTRUMENT
157 #include "TimeCounter.h"
160 #if USE(ACCELERATED_COMPOSITING)
161 #include "GraphicsLayerAndroid.h"
162 #include "RenderLayerCompositor.h"
169 // In some cases, too many invalidations passed to the UI will slow us down.
170 // Limit ourselves to 32 rectangles, past this just send the area bounds to the UI.
171 // see WebViewCore::recordPictureSet().
172 #define MAX_INVALIDATIONS 32
174 /* We pass this flag when recording the actual content, so that we don't spend
175 time actually regionizing complex path clips, when all we really want to do
178 #define PICT_RECORD_FLAGS SkPicture::kUsePathBoundsForClip_RecordingFlag
180 ////////////////////////////////////////////////////////////////////////////////////////////////
184 static SkTDArray<WebViewCore*> gInstanceList;
186 void WebViewCore::addInstance(WebViewCore* inst) {
187 *gInstanceList.append() = inst;
190 void WebViewCore::removeInstance(WebViewCore* inst) {
191 int index = gInstanceList.find(inst);
192 LOG_ASSERT(index >= 0, "RemoveInstance inst not found");
194 gInstanceList.removeShuffle(index);
198 bool WebViewCore::isInstance(WebViewCore* inst) {
199 return gInstanceList.find(inst) >= 0;
202 jobject WebViewCore::getApplicationContext() {
204 // check to see if there is a valid webviewcore object
205 if (gInstanceList.isEmpty())
208 // get the context from the webview
209 jobject context = gInstanceList[0]->getContext();
214 // get the application context using JNI
215 JNIEnv* env = JSC::Bindings::getJNIEnv();
216 jclass contextClass = env->GetObjectClass(context);
217 jmethodID appContextMethod = env->GetMethodID(contextClass, "getApplicationContext", "()Landroid/content/Context;");
218 env->DeleteLocalRef(contextClass);
219 jobject result = env->CallObjectMethod(context, appContextMethod);
225 struct WebViewCoreStaticMethods {
226 jmethodID m_isSupportedMediaMimeType;
227 } gWebViewCoreStaticMethods;
229 // Check whether a media mimeType is supported in Android media framework.
230 bool WebViewCore::isSupportedMediaMimeType(const WTF::String& mimeType) {
231 JNIEnv* env = JSC::Bindings::getJNIEnv();
232 jstring jMimeType = wtfStringToJstring(env, mimeType);
233 jclass webViewCore = env->FindClass("android/webkit/WebViewCore");
234 bool val = env->CallStaticBooleanMethod(webViewCore,
235 gWebViewCoreStaticMethods.m_isSupportedMediaMimeType, jMimeType);
237 env->DeleteLocalRef(webViewCore);
238 env->DeleteLocalRef(jMimeType);
243 // ----------------------------------------------------------------------------
245 #define GET_NATIVE_VIEW(env, obj) ((WebViewCore*)env->GetIntField(obj, gWebViewCoreFields.m_nativeClass))
247 // Field ids for WebViewCore
248 struct WebViewCoreFields {
249 jfieldID m_nativeClass;
250 jfieldID m_viewportWidth;
251 jfieldID m_viewportHeight;
252 jfieldID m_viewportInitialScale;
253 jfieldID m_viewportMinimumScale;
254 jfieldID m_viewportMaximumScale;
255 jfieldID m_viewportUserScalable;
256 jfieldID m_viewportDensityDpi;
258 jfieldID m_drawIsPaused;
259 jfieldID m_lowMemoryUsageMb;
260 jfieldID m_highMemoryUsageMb;
261 jfieldID m_highUsageDeltaMb;
262 } gWebViewCoreFields;
264 // ----------------------------------------------------------------------------
266 struct WebViewCore::JavaGlue {
268 jmethodID m_scrollTo;
269 jmethodID m_contentDraw;
270 jmethodID m_layersDraw;
271 jmethodID m_requestListBox;
272 jmethodID m_openFileChooser;
273 jmethodID m_requestSingleListBox;
275 jmethodID m_jsConfirm;
276 jmethodID m_jsPrompt;
277 jmethodID m_jsUnload;
278 jmethodID m_jsInterrupt;
279 jmethodID m_didFirstLayout;
280 jmethodID m_updateViewport;
281 jmethodID m_sendNotifyProgressFinished;
282 jmethodID m_sendViewInvalidate;
283 jmethodID m_updateTextfield;
284 jmethodID m_updateTextSelection;
285 jmethodID m_clearTextEntry;
286 jmethodID m_restoreScale;
287 jmethodID m_needTouchEvents;
288 jmethodID m_requestKeyboard;
289 jmethodID m_requestKeyboardWithSelection;
290 jmethodID m_exceededDatabaseQuota;
291 jmethodID m_reachedMaxAppCacheSize;
292 jmethodID m_populateVisitedLinks;
293 jmethodID m_geolocationPermissionsShowPrompt;
294 jmethodID m_geolocationPermissionsHidePrompt;
295 jmethodID m_getDeviceMotionService;
296 jmethodID m_getDeviceOrientationService;
297 jmethodID m_addMessageToConsole;
298 jmethodID m_formDidBlur;
299 jmethodID m_getPluginClass;
300 jmethodID m_showFullScreenPlugin;
301 jmethodID m_hideFullScreenPlugin;
302 jmethodID m_createSurface;
303 jmethodID m_addSurface;
304 jmethodID m_updateSurface;
305 jmethodID m_destroySurface;
306 jmethodID m_getContext;
307 jmethodID m_keepScreenOn;
308 jmethodID m_sendFindAgain;
309 jmethodID m_showRect;
310 jmethodID m_centerFitRect;
311 jmethodID m_setScrollbarModes;
312 jmethodID m_setInstallableWebApp;
313 jmethodID m_enterFullscreenForVideoLayer;
314 jmethodID m_setWebTextViewAutoFillable;
315 jmethodID m_selectAt;
316 AutoJObject object(JNIEnv* env) {
317 // We hold a weak reference to the Java WebViewCore to avoid memeory
318 // leaks due to circular references when WebView.destroy() is not
319 // called manually. The WebView and hence the WebViewCore could become
320 // weakly reachable at any time, after which the GC could null our weak
321 // reference, so we have to check the return value of this method at
322 // every use. Note that our weak reference will be nulled before the
323 // WebViewCore is finalized.
324 return getRealObject(env, m_obj);
329 * WebViewCore Implementation
332 static jmethodID GetJMethod(JNIEnv* env, jclass clazz, const char name[], const char signature[])
334 jmethodID m = env->GetMethodID(clazz, name, signature);
335 LOG_ASSERT(m, "Could not find method %s", name);
339 Mutex WebViewCore::gFrameCacheMutex;
340 Mutex WebViewCore::gCursorBoundsMutex;
342 WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* mainframe)
345 , m_moveGeneration(0)
346 , m_touchGeneration(0)
347 , m_lastGeneration(0)
348 , m_updatedFrameCache(true)
350 , m_hasCursorBounds(false)
351 , m_cursorBounds(WebCore::IntRect(0, 0, 0, 0))
352 , m_cursorHitBounds(WebCore::IntRect(0, 0, 0, 0))
354 , m_cursorLocation(WebCore::IntPoint(0, 0))
356 , m_javaGlue(new JavaGlue)
357 , m_mainFrame(mainframe)
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)
370 , m_maxXScroll(320/4)
371 , m_maxYScroll(240/4)
374 , m_mousePos(WebCore::IntPoint(0,0))
375 , m_frameCacheOutOfDate(true)
376 , m_progressDone(false)
378 , m_screenHeight(240)
379 , m_textWrapWidth(320)
381 , m_domtree_version(0)
382 , m_check_domtree_version(true)
383 , m_groupForVisitedLinks(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)
394 #if USE(CHROME_NETWORK_STACK)
395 , m_webRequestContext(0)
398 LOG_ASSERT(m_mainFrame, "Uh oh, somehow a frameview was made without an initial frame!");
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");
448 m_javaGlue->m_enterFullscreenForVideoLayer = GetJMethod(env, clazz, "enterFullscreenForVideoLayer", "(ILjava/lang/String;)V");
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);
454 env->SetIntField(javaWebViewCore, gWebViewCoreFields.m_nativeClass, (jint)this);
456 PageGroup::setShouldTrackVisitedLinks(true);
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));
464 WebViewCore::addInstance(this);
466 #if USE(CHROME_NETWORK_STACK)
467 AndroidNetworkLibraryImpl::InitWithApplicationContext(env, 0);
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
474 v8::V8::Initialize();
477 // Configure any RuntimeEnabled features that we need to change from their default now.
478 // See WebCore/bindings/generic/RuntimeEnabledFeatures.h
481 RuntimeEnabledFeatures::setPushStateEnabled(true);
484 WebViewCore::~WebViewCore()
486 WebViewCore::removeInstance(this);
488 // Release the focused view
489 Release(m_popupReply);
491 if (m_javaGlue->m_obj) {
492 JNIEnv* env = JSC::Bindings::getJNIEnv();
493 env->DeleteWeakGlobalRef(m_javaGlue->m_obj);
494 m_javaGlue->m_obj = 0;
497 delete m_frameCacheKit;
498 delete m_navPictureKit;
501 WebViewCore* WebViewCore::getWebViewCore(const WebCore::FrameView* view)
503 return getWebViewCore(static_cast<const WebCore::ScrollView*>(view));
506 WebViewCore* WebViewCore::getWebViewCore(const WebCore::ScrollView* view)
511 WebFrameView* webFrameView = static_cast<WebFrameView*>(view->platformWidget());
514 return webFrameView->webViewCore();
517 static bool layoutIfNeededRecursive(WebCore::Frame* f)
522 WebCore::FrameView* v = f->view();
526 if (v->needsLayout())
527 v->layout(f->tree()->parent());
529 WebCore::Frame* child = f->tree()->firstChild();
532 success &= layoutIfNeededRecursive(child);
533 child = child->tree()->nextSibling();
536 return success && !v->needsLayout();
539 CacheBuilder& WebViewCore::cacheBuilder()
541 return FrameLoaderClientAndroid::get(m_mainFrame)->getCacheBuilder();
544 WebCore::Node* WebViewCore::currentFocus()
546 return cacheBuilder().currentFocus();
549 void WebViewCore::recordPicture(SkPicture* picture)
551 // if there is no document yet, just return
552 if (!m_mainFrame->document()) {
553 DBG_NAV_LOG("no document");
556 // Call layout to ensure that the contentWidth and contentHeight are correct
557 if (!layoutIfNeededRecursive(m_mainFrame)) {
558 DBG_NAV_LOG("layout failed");
561 // draw into the picture's recording canvas
562 WebCore::FrameView* view = m_mainFrame->view();
563 DBG_NAV_LOGD("view=(w=%d,h=%d)", view->contentsWidth(),
564 view->contentsHeight());
565 SkAutoPictureRecord arp(picture, view->contentsWidth(),
566 view->contentsHeight(), PICT_RECORD_FLAGS);
567 SkAutoMemoryUsageProbe mup(__FUNCTION__);
569 WebCore::PlatformGraphicsContext pgc(arp.getRecordingCanvas());
570 WebCore::GraphicsContext gc(&pgc);
571 view->platformWidget()->draw(&gc, WebCore::IntRect(0, 0,
572 view->contentsWidth(), view->contentsHeight()));
575 void WebViewCore::recordPictureSet(PictureSet* content)
577 // if there is no document yet, just return
578 if (!m_mainFrame->document()) {
579 DBG_SET_LOG("!m_mainFrame->document()");
582 if (m_addInval.isEmpty()) {
583 DBG_SET_LOG("m_addInval.isEmpty()");
586 // Call layout to ensure that the contentWidth and contentHeight are correct
587 // it's fine for layout to gather invalidates, but defeat sending a message
588 // back to java to call webkitDraw, since we're already in the middle of
590 m_skipContentDraw = true;
591 bool success = layoutIfNeededRecursive(m_mainFrame);
592 m_skipContentDraw = false;
594 // We may be mid-layout and thus cannot draw.
598 { // collect WebViewCoreRecordTimeCounter after layoutIfNeededRecursive
599 #ifdef ANDROID_INSTRUMENT
600 TimeCounterAuto counter(TimeCounter::WebViewCoreRecordTimeCounter);
603 // if the webkit page dimensions changed, discard the pictureset and redraw.
604 WebCore::FrameView* view = m_mainFrame->view();
605 int width = view->contentsWidth();
606 int height = view->contentsHeight();
608 // Use the contents width and height as a starting point.
610 contentRect.set(0, 0, width, height);
611 SkIRect total(contentRect);
613 // Traverse all the frames and add their sizes if they are in the visible
615 for (WebCore::Frame* frame = m_mainFrame->tree()->traverseNext(); frame;
616 frame = frame->tree()->traverseNext()) {
617 // If the frame doesn't have an owner then it is the top frame and the
618 // view size is the frame size.
619 WebCore::RenderPart* owner = frame->ownerRenderer();
620 if (owner && owner->style()->visibility() == VISIBLE) {
624 // Traverse the tree up to the parent to find the absolute position
626 WebCore::Frame* parent = frame->tree()->parent();
628 WebCore::RenderPart* parentOwner = parent->ownerRenderer();
630 x += parentOwner->x();
631 y += parentOwner->y();
633 parent = parent->tree()->parent();
635 // Use the owner dimensions so that padding and border are
637 int right = x + owner->width();
638 int bottom = y + owner->height();
639 SkIRect frameRect = {x, y, right, bottom};
640 // Ignore a width or height that is smaller than 1. Some iframes
641 // have small dimensions in order to be hidden. The iframe
642 // expansion code does not expand in that case so we should ignore
644 if (frameRect.width() > 1 && frameRect.height() > 1
645 && SkIRect::Intersects(total, frameRect))
646 total.join(x, y, right, bottom);
650 // If the new total is larger than the content, resize the view to include
652 if (!contentRect.contains(total)) {
653 // Resize the view to change the overflow clip.
654 view->resize(total.fRight, total.fBottom);
656 // We have to force a layout in order for the clip to change.
657 m_mainFrame->contentRenderer()->setNeedsLayoutAndPrefWidthsRecalc();
660 // Relayout similar to above
661 m_skipContentDraw = true;
662 bool success = layoutIfNeededRecursive(m_mainFrame);
663 m_skipContentDraw = false;
667 // Set the computed content width
668 width = view->contentsWidth();
669 height = view->contentsHeight();
672 if (cacheBuilder().pictureSetDisabled())
675 #if USE(ACCELERATED_COMPOSITING)
676 // The invals are not always correct when the content size has changed. For
677 // now, let's just reset the inval so that it invalidates the entire content
678 // -- the pictureset will be fully repainted, tiles will be marked dirty and
679 // will have to be repainted.
681 // FIXME: the webkit invals ought to have been enough...
682 if (content->width() != width || content->height() != height) {
688 m_addInval.setRect(r);
692 content->setDimensions(width, height, &m_addInval);
694 // Add the current inval rects to the PictureSet, and rebuild it.
695 content->add(m_addInval, 0, 0, false);
697 // If we have too many invalidations, just get the area bounds
698 SkRegion::Iterator iterator(m_addInval);
700 while (!iterator.done()) {
703 if (nbInvals > MAX_INVALIDATIONS)
706 if (nbInvals > MAX_INVALIDATIONS) {
707 SkIRect r = m_addInval.getBounds();
708 m_addInval.setRect(r);
711 // Rebuild the pictureset (webkit repaint)
712 rebuildPictureSet(content);
713 } // WebViewCoreRecordTimeCounter
715 WebCore::Node* oldFocusNode = currentFocus();
716 m_frameCacheOutOfDate = true;
717 WebCore::IntRect oldBounds;
721 oldBounds = oldFocusNode->getRect();
722 RenderObject* renderer = oldFocusNode->renderer();
723 if (renderer && (renderer->isTextArea() || renderer->isTextField())) {
724 WebCore::RenderTextControl* rtc =
725 static_cast<WebCore::RenderTextControl*>(renderer);
726 oldSelStart = rtc->selectionStart();
727 oldSelEnd = rtc->selectionEnd();
730 oldBounds = WebCore::IntRect(0,0,0,0);
731 unsigned latestVersion = 0;
732 if (m_check_domtree_version) {
733 // as domTreeVersion only increment, we can just check the sum to see
734 // whether we need to update the frame cache
735 for (Frame* frame = m_mainFrame; frame; frame = frame->tree()->traverseNext()) {
736 const Document* doc = frame->document();
737 latestVersion += doc->domTreeVersion() + doc->styleVersion();
740 DBG_NAV_LOGD("m_lastFocused=%p oldFocusNode=%p"
741 " m_lastFocusedBounds={%d,%d,%d,%d} oldBounds={%d,%d,%d,%d}"
742 " m_lastFocusedSelection={%d,%d} oldSelection={%d,%d}"
743 " m_check_domtree_version=%s latestVersion=%d m_domtree_version=%d",
744 m_lastFocused, oldFocusNode,
745 m_lastFocusedBounds.x(), m_lastFocusedBounds.y(),
746 m_lastFocusedBounds.width(), m_lastFocusedBounds.height(),
747 oldBounds.x(), oldBounds.y(), oldBounds.width(), oldBounds.height(),
748 m_lastFocusedSelStart, m_lastFocusedSelEnd, oldSelStart, oldSelEnd,
749 m_check_domtree_version ? "true" : "false",
750 latestVersion, m_domtree_version);
751 if (m_lastFocused == oldFocusNode && m_lastFocusedBounds == oldBounds
752 && m_lastFocusedSelStart == oldSelStart
753 && m_lastFocusedSelEnd == oldSelEnd
755 && (!m_check_domtree_version || latestVersion == m_domtree_version))
759 m_focusBoundsChanged |= m_lastFocused == oldFocusNode
760 && m_lastFocusedBounds != oldBounds;
761 m_lastFocused = oldFocusNode;
762 m_lastFocusedBounds = oldBounds;
763 m_lastFocusedSelStart = oldSelStart;
764 m_lastFocusedSelEnd = oldSelEnd;
765 m_domtree_version = latestVersion;
766 DBG_NAV_LOG("call updateFrameCache");
769 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
770 JNIEnv* env = JSC::Bindings::getJNIEnv();
771 AutoJObject javaObject = m_javaGlue->object(env);
772 if (javaObject.get()) {
773 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_sendFindAgain);
779 // note: updateCursorBounds is called directly by the WebView thread
780 // This needs to be called each time we call CachedRoot::setCursor() with
781 // non-null CachedNode/CachedFrame, since otherwise the WebViewCore's data
782 // about the cursor is incorrect. When we call setCursor(0,0), we need
783 // to set hasCursorBounds to false.
784 void WebViewCore::updateCursorBounds(const CachedRoot* root,
785 const CachedFrame* cachedFrame, const CachedNode* cachedNode)
787 LOG_ASSERT(root, "updateCursorBounds: root cannot be null");
788 LOG_ASSERT(cachedNode, "updateCursorBounds: cachedNode cannot be null");
789 LOG_ASSERT(cachedFrame, "updateCursorBounds: cachedFrame cannot be null");
790 gCursorBoundsMutex.lock();
791 m_hasCursorBounds = !cachedNode->isHidden();
792 // If m_hasCursorBounds is false, we never look at the other
793 // values, so do not bother setting them.
794 if (m_hasCursorBounds) {
795 WebCore::IntRect bounds = cachedNode->bounds(cachedFrame);
796 if (m_cursorBounds != bounds)
797 DBG_NAV_LOGD("new cursor bounds=(%d,%d,w=%d,h=%d)",
798 bounds.x(), bounds.y(), bounds.width(), bounds.height());
799 m_cursorBounds = bounds;
800 m_cursorHitBounds = cachedNode->hitBounds(cachedFrame);
801 m_cursorFrame = cachedFrame->framePointer();
802 root->getSimulatedMousePosition(&m_cursorLocation);
803 m_cursorNode = cachedNode->nodePointer();
805 gCursorBoundsMutex.unlock();
808 void WebViewCore::clearContent()
812 m_addInval.setEmpty();
813 m_rebuildInval.setEmpty();
816 bool WebViewCore::focusBoundsChanged()
818 bool result = m_focusBoundsChanged;
819 m_focusBoundsChanged = false;
823 SkPicture* WebViewCore::rebuildPicture(const SkIRect& inval)
825 WebCore::FrameView* view = m_mainFrame->view();
826 int width = view->contentsWidth();
827 int height = view->contentsHeight();
828 SkPicture* picture = new SkPicture();
829 SkAutoPictureRecord arp(picture, width, height, PICT_RECORD_FLAGS);
830 SkAutoMemoryUsageProbe mup(__FUNCTION__);
831 SkCanvas* recordingCanvas = arp.getRecordingCanvas();
833 WebCore::PlatformGraphicsContext pgc(recordingCanvas);
834 WebCore::GraphicsContext gc(&pgc);
835 IntPoint origin = view->minimumScrollPosition();
836 WebCore::IntRect drawArea(inval.fLeft + origin.x(), inval.fTop + origin.y(),
837 inval.width(), inval.height());
838 recordingCanvas->translate(-drawArea.x(), -drawArea.y());
839 recordingCanvas->save();
840 view->platformWidget()->draw(&gc, drawArea);
841 m_rebuildInval.op(inval, SkRegion::kUnion_Op);
842 DBG_SET_LOGD("m_rebuildInval={%d,%d,r=%d,b=%d}",
843 m_rebuildInval.getBounds().fLeft, m_rebuildInval.getBounds().fTop,
844 m_rebuildInval.getBounds().fRight, m_rebuildInval.getBounds().fBottom);
849 void WebViewCore::rebuildPictureSet(PictureSet* pictureSet)
851 WebCore::FrameView* view = m_mainFrame->view();
853 #ifdef FAST_PICTURESET
854 WTF::Vector<Bucket*>* buckets = pictureSet->bucketsToUpdate();
856 for (unsigned int i = 0; i < buckets->size(); i++) {
857 Bucket* bucket = (*buckets)[i];
858 for (unsigned int j = 0; j < bucket->size(); j++) {
859 BucketPicture& bucketPicture = (*bucket)[j];
860 const SkIRect& inval = bucketPicture.mRealArea;
861 SkPicture* picture = rebuildPicture(inval);
862 SkSafeUnref(bucketPicture.mPicture);
863 bucketPicture.mPicture = picture;
868 size_t size = pictureSet->size();
869 for (size_t index = 0; index < size; index++) {
870 if (pictureSet->upToDate(index))
872 const SkIRect& inval = pictureSet->bounds(index);
873 DBG_SET_LOGD("pictSet=%p [%d] {%d,%d,w=%d,h=%d}", pictureSet, index,
874 inval.fLeft, inval.fTop, inval.width(), inval.height());
875 pictureSet->setPicture(index, rebuildPicture(inval));
878 pictureSet->validate(__FUNCTION__);
882 bool WebViewCore::updateLayers(LayerAndroid* layers)
884 // We update the layers
885 ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(m_mainFrame->page()->chrome()->client());
886 GraphicsLayerAndroid* root = static_cast<GraphicsLayerAndroid*>(chromeC->layersSync());
888 LayerAndroid* updatedLayer = root->contentLayer();
889 return layers->updateWithTree(updatedLayer);
894 void WebViewCore::notifyAnimationStarted()
896 // We notify webkit that the animations have begun
897 // TODO: handle case where not all have begun
898 ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(m_mainFrame->page()->chrome()->client());
899 GraphicsLayerAndroid* root = static_cast<GraphicsLayerAndroid*>(chromeC->layersSync());
901 root->notifyClientAnimationStarted();
905 BaseLayerAndroid* WebViewCore::createBaseLayer(SkRegion* region)
907 BaseLayerAndroid* base = new BaseLayerAndroid();
908 base->setContent(m_content);
910 m_skipContentDraw = true;
911 bool layoutSucceeded = layoutIfNeededRecursive(m_mainFrame);
912 m_skipContentDraw = false;
913 // Layout only fails if called during a layout.
914 LOG_ASSERT(layoutSucceeded, "Can never be called recursively");
916 #if USE(ACCELERATED_COMPOSITING)
917 // We set the background color
918 if (m_mainFrame && m_mainFrame->document()
919 && m_mainFrame->document()->body()) {
920 Document* document = m_mainFrame->document();
921 RefPtr<RenderStyle> style = document->styleForElementIgnoringPendingStylesheets(document->body());
922 if (style->hasBackground()) {
923 Color color = style->visitedDependentColor(CSSPropertyBackgroundColor);
924 if (color.isValid() && color.alpha() > 0)
925 base->setBackgroundColor(color);
929 // We update the layers
930 ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(m_mainFrame->page()->chrome()->client());
931 GraphicsLayerAndroid* root = static_cast<GraphicsLayerAndroid*>(chromeC->layersSync());
933 LayerAndroid* copyLayer = new LayerAndroid(*root->contentLayer());
934 base->addChild(copyLayer);
936 root->contentLayer()->clearDirtyRegion();
943 BaseLayerAndroid* WebViewCore::recordContent(SkRegion* region, SkIPoint* point)
945 DBG_SET_LOG("start");
946 // If there is a pending style recalculation, just return.
947 if (m_mainFrame->document()->isPendingStyleRecalc()) {
948 DBG_SET_LOGD("recordContent: pending style recalc, ignoring.");
951 float progress = (float) m_mainFrame->page()->progress()->estimatedProgress();
952 m_progressDone = progress <= 0.0f || progress >= 1.0f;
953 recordPictureSet(&m_content);
954 if (!m_progressDone && m_content.isEmpty()) {
955 DBG_SET_LOGD("empty (progress=%g)", progress);
958 region->set(m_addInval);
959 m_addInval.setEmpty();
960 #if USE(ACCELERATED_COMPOSITING)
962 region->op(m_rebuildInval, SkRegion::kUnion_Op);
964 m_rebuildInval.setEmpty();
965 point->fX = m_content.width();
966 point->fY = m_content.height();
967 DBG_SET_LOGD("region={%d,%d,r=%d,b=%d}", region->getBounds().fLeft,
968 region->getBounds().fTop, region->getBounds().fRight,
969 region->getBounds().fBottom);
972 return createBaseLayer(region);
975 void WebViewCore::splitContent(PictureSet* content)
977 #ifdef FAST_PICTURESET
979 bool layoutSucceeded = layoutIfNeededRecursive(m_mainFrame);
980 LOG_ASSERT(layoutSucceeded, "Can never be called recursively");
981 content->split(&m_content);
982 rebuildPictureSet(&m_content);
983 content->set(m_content);
984 #endif // FAST_PICTURESET
987 void WebViewCore::scrollTo(int x, int y, bool animate)
989 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
991 // LOGD("WebViewCore::scrollTo(%d %d)\n", x, y);
993 JNIEnv* env = JSC::Bindings::getJNIEnv();
994 AutoJObject javaObject = m_javaGlue->object(env);
995 if (!javaObject.get())
997 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_scrollTo,
998 x, y, animate, false);
1002 void WebViewCore::sendNotifyProgressFinished()
1004 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
1005 JNIEnv* env = JSC::Bindings::getJNIEnv();
1006 AutoJObject javaObject = m_javaGlue->object(env);
1007 if (!javaObject.get())
1009 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_sendNotifyProgressFinished);
1010 checkException(env);
1013 void WebViewCore::viewInvalidate(const WebCore::IntRect& rect)
1015 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
1016 JNIEnv* env = JSC::Bindings::getJNIEnv();
1017 AutoJObject javaObject = m_javaGlue->object(env);
1018 if (!javaObject.get())
1020 env->CallVoidMethod(javaObject.get(),
1021 m_javaGlue->m_sendViewInvalidate,
1022 rect.x(), rect.y(), rect.maxX(), rect.maxY());
1023 checkException(env);
1026 void WebViewCore::contentDraw()
1028 JNIEnv* env = JSC::Bindings::getJNIEnv();
1029 AutoJObject javaObject = m_javaGlue->object(env);
1030 if (!javaObject.get())
1032 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_contentDraw);
1033 checkException(env);
1036 void WebViewCore::layersDraw()
1038 JNIEnv* env = JSC::Bindings::getJNIEnv();
1039 AutoJObject javaObject = m_javaGlue->object(env);
1040 if (!javaObject.get())
1042 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_layersDraw);
1043 checkException(env);
1046 void WebViewCore::contentInvalidate(const WebCore::IntRect &r)
1048 DBG_SET_LOGD("rect={%d,%d,w=%d,h=%d}", r.x(), r.y(), r.width(), r.height());
1050 if (!rect.intersect(0, 0, INT_MAX, INT_MAX))
1052 m_addInval.op(rect, SkRegion::kUnion_Op);
1053 DBG_SET_LOGD("m_addInval={%d,%d,r=%d,b=%d}",
1054 m_addInval.getBounds().fLeft, m_addInval.getBounds().fTop,
1055 m_addInval.getBounds().fRight, m_addInval.getBounds().fBottom);
1056 if (!m_skipContentDraw)
1060 void WebViewCore::contentInvalidateAll()
1062 WebCore::FrameView* view = m_mainFrame->view();
1063 contentInvalidate(WebCore::IntRect(0, 0,
1064 view->contentsWidth(), view->contentsHeight()));
1067 void WebViewCore::offInvalidate(const WebCore::IntRect &r)
1069 // FIXME: these invalidates are offscreen, and can be throttled or
1070 // deferred until the area is visible. For now, treat them as
1071 // regular invals so that drawing happens (inefficiently) for now.
1072 contentInvalidate(r);
1075 static int pin_pos(int x, int width, int targetWidth)
1077 if (x + width > targetWidth)
1078 x = targetWidth - width;
1084 void WebViewCore::didFirstLayout()
1086 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
1087 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
1089 JNIEnv* env = JSC::Bindings::getJNIEnv();
1090 AutoJObject javaObject = m_javaGlue->object(env);
1091 if (!javaObject.get())
1094 const WebCore::KURL& url = m_mainFrame->document()->url();
1097 LOGV("::WebCore:: didFirstLayout %s", url.string().ascii().data());
1099 WebCore::FrameLoadType loadType = m_mainFrame->loader()->loadType();
1101 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_didFirstLayout,
1102 loadType == WebCore::FrameLoadTypeStandard
1103 // When redirect with locked history, we would like to reset the
1104 // scale factor. This is important for www.yahoo.com as it is
1105 // redirected to www.yahoo.com/?rs=1 on load.
1106 || loadType == WebCore::FrameLoadTypeRedirectWithLockedBackForwardList
1107 // When "request desktop page" is used, we want to treat it as
1108 // a newly-loaded page.
1109 || loadType == WebCore::FrameLoadTypeSame);
1110 checkException(env);
1112 DBG_NAV_LOG("call updateFrameCache");
1113 m_check_domtree_version = false;
1115 m_history.setDidFirstLayout(true);
1118 void WebViewCore::updateViewport()
1120 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
1121 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
1123 JNIEnv* env = JSC::Bindings::getJNIEnv();
1124 AutoJObject javaObject = m_javaGlue->object(env);
1125 if (!javaObject.get())
1127 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_updateViewport);
1128 checkException(env);
1131 void WebViewCore::restoreScale(float scale, float textWrapScale)
1133 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
1134 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
1136 JNIEnv* env = JSC::Bindings::getJNIEnv();
1137 AutoJObject javaObject = m_javaGlue->object(env);
1138 if (!javaObject.get())
1140 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_restoreScale, scale, textWrapScale);
1141 checkException(env);
1144 void WebViewCore::needTouchEvents(bool need)
1146 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
1147 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
1149 #if ENABLE(TOUCH_EVENTS)
1150 JNIEnv* env = JSC::Bindings::getJNIEnv();
1151 AutoJObject javaObject = m_javaGlue->object(env);
1152 if (!javaObject.get())
1155 if (m_forwardingTouchEvents == need)
1158 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_needTouchEvents, need);
1159 checkException(env);
1161 m_forwardingTouchEvents = need;
1165 void WebViewCore::requestKeyboardWithSelection(const WebCore::Node* node,
1166 int selStart, int selEnd)
1168 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
1169 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
1171 JNIEnv* env = JSC::Bindings::getJNIEnv();
1172 AutoJObject javaObject = m_javaGlue->object(env);
1173 if (!javaObject.get())
1175 env->CallVoidMethod(javaObject.get(),
1176 m_javaGlue->m_requestKeyboardWithSelection,
1177 reinterpret_cast<int>(node), selStart, selEnd, m_textGeneration);
1178 checkException(env);
1181 void WebViewCore::requestKeyboard(bool showKeyboard)
1183 DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
1184 LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!");
1186 JNIEnv* env = JSC::Bindings::getJNIEnv();
1187 AutoJObject javaObject = m_javaGlue->object(env);
1188 if (!javaObject.get())
1190 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_requestKeyboard, showKeyboard);
1191 checkException(env);
1194 void WebViewCore::notifyProgressFinished()
1196 m_check_domtree_version = true;
1197 sendNotifyProgressFinished();
1200 void WebViewCore::doMaxScroll(CacheBuilder::Direction dir)
1205 case CacheBuilder::LEFT:
1208 case CacheBuilder::UP:
1211 case CacheBuilder::RIGHT:
1214 case CacheBuilder::DOWN:
1217 case CacheBuilder::UNINITIALIZED:
1219 LOG_ASSERT(0, "unexpected focus selector");
1221 WebCore::FrameView* view = m_mainFrame->view();
1222 this->scrollTo(view->scrollX() + dx, view->scrollY() + dy, true);
1225 void WebViewCore::setScrollOffset(int moveGeneration, bool sendScrollEvent, int dx, int dy)
1227 DBG_NAV_LOGD("{%d,%d} m_scrollOffset=(%d,%d), sendScrollEvent=%d", dx, dy,
1228 m_scrollOffsetX, m_scrollOffsetY, sendScrollEvent);
1229 if (m_scrollOffsetX != dx || m_scrollOffsetY != dy) {
1230 m_scrollOffsetX = dx;
1231 m_scrollOffsetY = dy;
1232 // The visible rect is located within our coordinate space so it
1233 // contains the actual scroll position. Setting the location makes hit
1234 // testing work correctly.
1235 m_mainFrame->view()->platformWidget()->setLocation(m_scrollOffsetX,
1237 if (sendScrollEvent) {
1238 m_mainFrame->eventHandler()->sendScrollEvent();
1240 // Only update history position if it's user scrolled.
1241 // Update history item to reflect the new scroll position.
1242 // This also helps save the history information when the browser goes to
1243 // background, so scroll position will be restored if browser gets
1244 // killed while in background.
1245 WebCore::HistoryController* history = m_mainFrame->loader()->history();
1246 // Because the history item saving could be heavy for large sites and
1247 // scrolling can generate lots of small scroll offset, the following code
1248 // reduces the saving frequency.
1249 static const int MIN_SCROLL_DIFF = 32;
1250 if (history->currentItem()) {
1251 WebCore::IntPoint currentPoint = history->currentItem()->scrollPoint();
1252 if (std::abs(currentPoint.x() - dx) >= MIN_SCROLL_DIFF ||
1253 std::abs(currentPoint.y() - dy) >= MIN_SCROLL_DIFF) {
1254 history->saveScrollPositionAndViewStateToItem(history->currentItem());
1259 // update the currently visible screen
1260 sendPluginVisibleScreen();
1262 gCursorBoundsMutex.lock();
1263 bool hasCursorBounds = m_hasCursorBounds;
1264 Frame* frame = (Frame*) m_cursorFrame;
1265 IntPoint location = m_cursorLocation;
1266 gCursorBoundsMutex.unlock();
1267 if (!hasCursorBounds)
1269 moveMouseIfLatest(moveGeneration, frame, location.x(), location.y());
1272 void WebViewCore::setGlobalBounds(int x, int y, int h, int v)
1274 DBG_NAV_LOGD("{%d,%d}", x, y);
1275 m_mainFrame->view()->platformWidget()->setWindowBounds(x, y, h, v);
1278 void WebViewCore::setSizeScreenWidthAndScale(int width, int height,
1279 int textWrapWidth, float scale, int screenWidth, int screenHeight,
1280 int anchorX, int anchorY, bool ignoreHeight)
1282 // Ignore the initial empty document.
1283 const WebCore::KURL& url = m_mainFrame->document()->url();
1287 WebCoreViewBridge* window = m_mainFrame->view()->platformWidget();
1288 int ow = window->width();
1289 int oh = window->height();
1290 int osw = m_screenWidth;
1291 int osh = m_screenHeight;
1292 int otw = m_textWrapWidth;
1293 float oldScale = m_scale;
1294 DBG_NAV_LOGD("old:(w=%d,h=%d,sw=%d,scale=%g) new:(w=%d,h=%d,sw=%d,scale=%g)",
1295 ow, oh, osw, m_scale, width, height, screenWidth, scale);
1296 m_screenWidth = screenWidth;
1297 m_screenHeight = screenHeight;
1298 m_textWrapWidth = textWrapWidth;
1299 if (scale >= 0) // negative means keep the current scale
1301 m_maxXScroll = screenWidth >> 2;
1302 m_maxYScroll = m_maxXScroll * height / width;
1303 // Don't reflow if the diff is small.
1304 const bool reflow = otw && textWrapWidth &&
1305 ((float) abs(otw - textWrapWidth) / textWrapWidth) >= 0.01f;
1307 // When the screen size change, fixed positioned element should be updated.
1308 // This is supposed to be light weighted operation without a full layout.
1309 if (osh != screenHeight || osw != screenWidth)
1310 m_mainFrame->view()->updatePositionedObjects();
1312 if (ow != width || (!ignoreHeight && oh != height) || reflow) {
1313 WebCore::RenderObject *r = m_mainFrame->contentRenderer();
1314 DBG_NAV_LOGD("renderer=%p view=(w=%d,h=%d)", r,
1315 screenWidth, screenHeight);
1317 WebCore::IntPoint anchorPoint = WebCore::IntPoint(anchorX, anchorY);
1318 DBG_NAV_LOGD("anchorX=%d anchorY=%d", anchorX, anchorY);
1319 RefPtr<WebCore::Node> node;
1320 WebCore::IntRect bounds;
1321 WebCore::IntPoint offset;
1322 // If the text wrap changed, it is probably zoom change or
1323 // orientation change. Try to keep the anchor at the same place.
1324 if (otw && textWrapWidth && otw != textWrapWidth &&
1325 (anchorX != 0 || anchorY != 0)) {
1326 WebCore::HitTestResult hitTestResult =
1327 m_mainFrame->eventHandler()->hitTestResultAtPoint(
1328 anchorPoint, false);
1329 node = hitTestResult.innerNode();
1332 bounds = node->getRect();
1333 DBG_NAV_LOGD("ob:(x=%d,y=%d,w=%d,h=%d)",
1334 bounds.x(), bounds.y(), bounds.width(), bounds.height());
1335 // sites like nytimes.com insert a non-standard tag <nyt_text>
1336 // in the html. If it is the HitTestResult, it may have zero
1337 // width and height. In this case, use its parent node.
1338 if (bounds.width() == 0) {
1339 node = node->parentOrHostNode();
1341 bounds = node->getRect();
1342 DBG_NAV_LOGD("found a zero width node and use its parent, whose ob:(x=%d,y=%d,w=%d,h=%d)",
1343 bounds.x(), bounds.y(), bounds.width(), bounds.height());
1348 // Set the size after finding the old anchor point as
1349 // hitTestResultAtPoint causes a layout.
1350 window->setSize(width, height);
1351 window->setVisibleSize(screenWidth, screenHeight);
1352 if (width != screenWidth) {
1353 m_mainFrame->view()->setUseFixedLayout(true);
1354 m_mainFrame->view()->setFixedLayoutSize(IntSize(width, height));
1356 m_mainFrame->view()->setUseFixedLayout(false);
1357 r->setNeedsLayoutAndPrefWidthsRecalc();
1358 if (m_mainFrame->view()->didFirstLayout())
1359 m_mainFrame->view()->forceLayout();
1361 // scroll to restore current screen center
1363 const WebCore::IntRect& newBounds = node->getRect();
1364 DBG_NAV_LOGD("nb:(x=%d,y=%d,w=%d,"
1365 "h=%d)", newBounds.x(), newBounds.y(),
1366 newBounds.width(), newBounds.height());
1367 if ((osw && osh && bounds.width() && bounds.height())
1368 && (bounds != newBounds)) {
1369 WebCore::FrameView* view = m_mainFrame->view();
1370 // force left align if width is not changed while height changed.
1371 // the anchorPoint is probably at some white space in the node
1372 // which is affected by text wrap around the screen width.
1373 const bool leftAlign = (otw != textWrapWidth)
1374 && (bounds.width() == newBounds.width())
1375 && (bounds.height() != newBounds.height());
1376 const float xPercentInDoc =
1377 leftAlign ? 0.0 : (float) (anchorX - bounds.x()) / bounds.width();
1378 const float xPercentInView =
1379 leftAlign ? 0.0 : (float) (anchorX - m_scrollOffsetX) / osw;
1380 const float yPercentInDoc = (float) (anchorY - bounds.y()) / bounds.height();
1381 const float yPercentInView = (float) (anchorY - m_scrollOffsetY) / osh;
1382 showRect(newBounds.x(), newBounds.y(), newBounds.width(),
1383 newBounds.height(), view->contentsWidth(),
1384 view->contentsHeight(),
1385 xPercentInDoc, xPercentInView,
1386 yPercentInDoc, yPercentInView);
1391 window->setSize(width, height);
1392 window->setVisibleSize(screenWidth, screenHeight);
1393 m_mainFrame->view()->resize(width, height);
1394 if (width != screenWidth) {
1395 m_mainFrame->view()->setUseFixedLayout(true);
1396 m_mainFrame->view()->setFixedLayoutSize(IntSize(width, height));
1398 m_mainFrame->view()->setUseFixedLayout(false);
1401 // update the currently visible screen as perceived by the plugin
1402 sendPluginVisibleScreen();
1405 void WebViewCore::dumpDomTree(bool useFile)
1407 #ifdef ANDROID_DOM_LOGGING
1409 gDomTreeFile = fopen(DOM_TREE_LOG_FILE, "w");
1410 m_mainFrame->document()->showTreeForThis();
1412 fclose(gDomTreeFile);
1418 void WebViewCore::dumpRenderTree(bool useFile)
1420 #ifdef ANDROID_DOM_LOGGING
1421 WTF::CString renderDump = WebCore::externalRepresentation(m_mainFrame).utf8();
1422 const char* data = renderDump.data();
1424 gRenderTreeFile = fopen(RENDER_TREE_LOG_FILE, "w");
1425 DUMP_RENDER_LOGD("%s", data);
1426 fclose(gRenderTreeFile);
1427 gRenderTreeFile = 0;
1429 // adb log can only output 1024 characters, so write out line by line.
1430 // exclude '\n' as adb log adds it for each output.
1431 int length = renderDump.length();
1432 for (int i = 0, last = 0; i < length; i++) {
1433 if (data[i] == '\n') {
1435 DUMP_RENDER_LOGD("%.*s", (i - last), &(data[last]));
1443 void WebViewCore::dumpNavTree()
1446 cacheBuilder().mDebug.print();
1450 HTMLElement* WebViewCore::retrieveElement(int x, int y,
1451 const QualifiedName& tagName)
1453 HitTestResult hitTestResult = m_mainFrame->eventHandler()
1454 ->hitTestResultAtPoint(IntPoint(x, y), false, false,
1455 DontHitTestScrollbars, HitTestRequest::Active | HitTestRequest::ReadOnly,
1457 if (!hitTestResult.innerNode() || !hitTestResult.innerNode()->inDocument()) {
1458 LOGE("Should not happen: no in document Node found");
1461 const ListHashSet<RefPtr<Node> >& list = hitTestResult.rectBasedTestResult();
1462 if (list.isEmpty()) {
1463 LOGE("Should not happen: no rect-based-test nodes found");
1466 Node* node = hitTestResult.innerNode();
1467 Node* element = node;
1468 while (element && (!element->isElementNode()
1469 || !element->hasTagName(tagName))) {
1470 element = element->parentNode();
1472 DBG_NAV_LOGD("node=%p element=%p x=%d y=%d nodeName=%s tagName=%s", node,
1473 element, x, y, node->nodeName().utf8().data(),
1474 element ? ((Element*) element)->tagName().utf8().data() : "<none>");
1475 return static_cast<WebCore::HTMLElement*>(element);
1478 HTMLAnchorElement* WebViewCore::retrieveAnchorElement(int x, int y)
1480 return static_cast<HTMLAnchorElement*>
1481 (retrieveElement(x, y, HTMLNames::aTag));
1484 HTMLImageElement* WebViewCore::retrieveImageElement(int x, int y)
1486 return static_cast<HTMLImageElement*>
1487 (retrieveElement(x, y, HTMLNames::imgTag));
1490 WTF::String WebViewCore::retrieveHref(int x, int y)
1492 WebCore::HTMLAnchorElement* anchor = retrieveAnchorElement(x, y);
1493 return anchor ? anchor->href() : WTF::String();
1496 WTF::String WebViewCore::retrieveAnchorText(int x, int y)
1498 WebCore::HTMLAnchorElement* anchor = retrieveAnchorElement(x, y);
1499 return anchor ? anchor->text() : WTF::String();
1502 WTF::String WebViewCore::retrieveImageSource(int x, int y)
1504 HTMLImageElement* image = retrieveImageElement(x, y);
1505 return image ? image->src().string() : WTF::String();
1508 WTF::String WebViewCore::requestLabel(WebCore::Frame* frame,
1509 WebCore::Node* node)
1511 if (node && CacheBuilder::validNode(m_mainFrame, frame, node)) {
1512 RefPtr<WebCore::NodeList> list = node->document()->getElementsByTagName("label");
1513 unsigned length = list->length();
1514 for (unsigned i = 0; i < length; i++) {
1515 WebCore::HTMLLabelElement* label = static_cast<WebCore::HTMLLabelElement*>(
1517 if (label->control() == node) {
1520 while ((node = node->traverseNextNode(label))) {
1521 if (node->isTextNode()) {
1522 Text* textNode = static_cast<Text*>(node);
1523 result += textNode->dataImpl();
1530 return WTF::String();
1533 static bool isContentEditable(const WebCore::Node* node)
1535 if (!node) return false;
1536 return node->document()->frame()->selection()->isContentEditable();
1539 // Returns true if the node is a textfield, textarea, or contentEditable
1540 static bool isTextInput(const WebCore::Node* node)
1542 if (isContentEditable(node))
1546 WebCore::RenderObject* renderer = node->renderer();
1547 return renderer && (renderer->isTextField() || renderer->isTextArea());
1550 void WebViewCore::revealSelection()
1552 WebCore::Node* focus = currentFocus();
1555 if (!isTextInput(focus))
1557 WebCore::Frame* focusedFrame = focus->document()->frame();
1558 if (!focusedFrame->page()->focusController()->isActive())
1560 focusedFrame->selection()->revealSelection(ScrollAlignment::alignToEdgeIfNeeded);
1563 void WebViewCore::updateCacheOnNodeChange()
1565 gCursorBoundsMutex.lock();
1566 bool hasCursorBounds = m_hasCursorBounds;
1567 Frame* frame = (Frame*) m_cursorFrame;
1568 Node* node = (Node*) m_cursorNode;
1569 IntRect bounds = m_cursorHitBounds;
1570 gCursorBoundsMutex.unlock();
1571 if (!hasCursorBounds || !node)
1573 if (CacheBuilder::validNode(m_mainFrame, frame, node)) {
1574 RenderObject* renderer = node->renderer();
1575 if (renderer && renderer->style()->visibility() != HIDDEN) {
1576 IntRect absBox = renderer->absoluteBoundingBoxRect();
1577 int globalX, globalY;
1578 CacheBuilder::GetGlobalOffset(frame, &globalX, &globalY);
1579 absBox.move(globalX, globalY);
1580 if (absBox == bounds)
1582 DBG_NAV_LOGD("absBox=(%d,%d,%d,%d) bounds=(%d,%d,%d,%d)",
1583 absBox.x(), absBox.y(), absBox.width(), absBox.height(),
1584 bounds.x(), bounds.y(), bounds.width(), bounds.height());
1587 DBG_NAV_LOGD("updateFrameCache node=%p", node);
1591 void WebViewCore::updateFrameCache()
1593 if (!m_frameCacheOutOfDate) {
1594 DBG_NAV_LOG("!m_frameCacheOutOfDate");
1598 // If there is a pending style recalculation, do not update the frame cache.
1599 // Until the recalculation is complete, there may be internal objects that
1600 // are in an inconsistent state (such as font pointers).
1601 // In any event, there's not much point to updating the cache while a style
1602 // recalculation is pending, since it will simply have to be updated again
1603 // once the recalculation is complete.
1604 // TODO: Do we need to reschedule an update for after the style is recalculated?
1605 if (m_mainFrame && m_mainFrame->document() && m_mainFrame->document()->isPendingStyleRecalc()) {
1606 LOGW("updateFrameCache: pending style recalc, ignoring.");
1609 #ifdef ANDROID_INSTRUMENT
1610 TimeCounterAuto counter(TimeCounter::WebViewCoreBuildNavTimeCounter);
1612 m_frameCacheOutOfDate = false;
1613 m_temp = new CachedRoot();
1614 m_temp->init(m_mainFrame, &m_history);
1615 #if USE(ACCELERATED_COMPOSITING)
1616 GraphicsLayerAndroid* graphicsLayer = graphicsRootLayer();
1618 m_temp->setRootLayer(graphicsLayer->contentLayer());
1620 CacheBuilder& builder = cacheBuilder();
1621 WebCore::Settings* settings = m_mainFrame->page()->settings();
1622 builder.allowAllTextDetection();
1623 #ifdef ANDROID_META_SUPPORT
1625 if (!settings->formatDetectionAddress())
1626 builder.disallowAddressDetection();
1627 if (!settings->formatDetectionEmail())
1628 builder.disallowEmailDetection();
1629 if (!settings->formatDetectionTelephone())
1630 builder.disallowPhoneDetection();
1633 builder.buildCache(m_temp);
1634 m_tempPict = new SkPicture();
1635 recordPicture(m_tempPict);
1636 m_temp->setPicture(m_tempPict);
1637 m_temp->setTextGeneration(m_textGeneration);
1638 WebCoreViewBridge* window = m_mainFrame->view()->platformWidget();
1639 m_temp->setVisibleRect(WebCore::IntRect(m_scrollOffsetX,
1640 m_scrollOffsetY, window->width(), window->height()));
1641 gFrameCacheMutex.lock();
1642 delete m_frameCacheKit;
1643 delete m_navPictureKit;
1644 m_frameCacheKit = m_temp;
1645 m_navPictureKit = m_tempPict;
1646 m_updatedFrameCache = true;
1648 const CachedNode* cachedFocusNode = m_frameCacheKit->currentFocus();
1649 DBG_NAV_LOGD("cachedFocusNode=%d (nodePointer=%p)",
1650 cachedFocusNode ? cachedFocusNode->index() : 0,
1651 cachedFocusNode ? cachedFocusNode->nodePointer() : 0);
1653 gFrameCacheMutex.unlock();
1656 void WebViewCore::updateFrameCacheIfLoading()
1658 if (!m_check_domtree_version)
1662 struct TouchNodeData {
1667 // get the bounding box of the Node
1668 static IntRect getAbsoluteBoundingBox(Node* node) {
1670 RenderObject* render = node->renderer();
1671 if (render->isRenderInline())
1672 rect = toRenderInline(render)->linesVisualOverflowBoundingBox();
1673 else if (render->isBox())
1674 rect = toRenderBox(render)->visualOverflowRect();
1675 else if (render->isText())
1676 rect = toRenderText(render)->linesBoundingBox();
1678 LOGE("getAbsoluteBoundingBox failed for node %p, name %s", node, render->renderName());
1679 FloatPoint absPos = render->localToAbsolute();
1680 rect.move(absPos.x(), absPos.y());
1684 // get the highlight rectangles for the touch point (x, y) with the slop
1685 Vector<IntRect> WebViewCore::getTouchHighlightRects(int x, int y, int slop)
1687 Vector<IntRect> rects;
1688 m_mousePos = IntPoint(x - m_scrollOffsetX, y - m_scrollOffsetY);
1689 HitTestResult hitTestResult = m_mainFrame->eventHandler()->hitTestResultAtPoint(IntPoint(x, y),
1690 false, false, DontHitTestScrollbars, HitTestRequest::Active | HitTestRequest::ReadOnly, IntSize(slop, slop));
1691 if (!hitTestResult.innerNode() || !hitTestResult.innerNode()->inDocument()) {
1692 LOGE("Should not happen: no in document Node found");
1695 const ListHashSet<RefPtr<Node> >& list = hitTestResult.rectBasedTestResult();
1696 if (list.isEmpty()) {
1697 LOGE("Should not happen: no rect-based-test nodes found");
1700 Frame* frame = hitTestResult.innerNode()->document()->frame();
1701 Vector<TouchNodeData> nodeDataList;
1702 ListHashSet<RefPtr<Node> >::const_iterator last = list.end();
1703 for (ListHashSet<RefPtr<Node> >::const_iterator it = list.begin(); it != last; ++it) {
1704 // TODO: it seems reasonable to not search across the frame. Isn't it?
1705 // if the node is not in the same frame as the innerNode, skip it
1706 if (it->get()->document()->frame() != frame)
1708 // traverse up the tree to find the first node that needs highlight
1710 Node* eventNode = it->get();
1712 RenderObject* render = eventNode->renderer();
1713 if (render && (render->isBody() || render->isRenderView()))
1715 if (eventNode->supportsFocus()
1716 || eventNode->hasEventListeners(eventNames().clickEvent)
1717 || eventNode->hasEventListeners(eventNames().mousedownEvent)
1718 || eventNode->hasEventListeners(eventNames().mouseupEvent)) {
1722 // the nodes in the rectBasedTestResult() are ordered based on z-index during hit testing.
1723 // so do not search for the eventNode across explicit z-index border.
1724 // TODO: this is a hard one to call. z-index is quite complicated as its value only
1725 // matters when you compare two RenderLayer in the same hierarchy level. e.g. in
1726 // the following example, "b" is on the top as its z level is the highest. even "c"
1727 // has 100 as z-index, it is still below "d" as its parent has the same z-index as
1728 // "d" and logically before "d". Of course "a" is the lowest in the z level.
1736 // If the fat point touches everyone, the order in the list should be "b", "d", "c"
1737 // and "a". When we search for the event node for "b", we really don't want "a" as
1738 // in the z-order it is behind everything else.
1739 if (render && !render->style()->hasAutoZIndex())
1741 eventNode = eventNode->parentNode();
1743 // didn't find any eventNode, skip it
1746 // first quick check whether it is a duplicated node before computing bounding box
1747 Vector<TouchNodeData>::const_iterator nlast = nodeDataList.end();
1748 for (Vector<TouchNodeData>::const_iterator n = nodeDataList.begin(); n != nlast; ++n) {
1749 // found the same node, skip it
1750 if (eventNode == n->mNode) {
1757 // next check whether the node is fully covered by or fully covering another node.
1759 IntRect rect = getAbsoluteBoundingBox(eventNode);
1760 if (rect.isEmpty()) {
1761 // if the node's bounds is empty and it is not a ContainerNode, skip it.
1762 if (!eventNode->isContainerNode())
1764 // if the node's children are all positioned objects, its bounds can be empty.
1765 // Walk through the children to find the bounding box.
1766 Node* child = static_cast<const ContainerNode*>(eventNode)->firstChild();
1769 if (child->renderer())
1770 childrect = getAbsoluteBoundingBox(child);
1771 if (!childrect.isEmpty()) {
1772 rect.unite(childrect);
1773 child = child->traverseNextSibling(eventNode);
1775 child = child->traverseNextNode(eventNode);
1778 for (int i = nodeDataList.size() - 1; i >= 0; i--) {
1779 TouchNodeData n = nodeDataList.at(i);
1780 // the new node is enclosing an existing node, skip it
1781 if (rect.contains(n.mBounds)) {
1785 // the new node is fully inside an existing node, remove the existing node
1786 if (n.mBounds.contains(rect))
1787 nodeDataList.remove(i);
1790 TouchNodeData newNode;
1791 newNode.mNode = eventNode;
1792 newNode.mBounds = rect;
1793 nodeDataList.append(newNode);
1796 if (!nodeDataList.size())
1798 // finally select the node with the largest overlap with the fat point
1799 TouchNodeData final;
1801 IntPoint docPos = frame->view()->windowToContents(m_mousePos);
1802 IntRect testRect(docPos.x() - slop, docPos.y() - slop, 2 * slop + 1, 2 * slop + 1);
1804 Vector<TouchNodeData>::const_iterator nlast = nodeDataList.end();
1805 for (Vector<TouchNodeData>::const_iterator n = nodeDataList.begin(); n != nlast; ++n) {
1806 IntRect rect = n->mBounds;
1807 rect.intersect(testRect);
1808 int a = rect.width() * rect.height();
1814 // now get the node's highlight rectangles in the page coordinate system
1816 IntPoint frameAdjust;
1817 if (frame != m_mainFrame) {
1818 frameAdjust = frame->view()->contentsToWindow(IntPoint());
1819 frameAdjust.move(m_scrollOffsetX, m_scrollOffsetY);
1821 if (final.mNode->isLink()) {
1822 // most of the links are inline instead of box style. So the bounding box is not
1823 // a good representation for the highlights. Get the list of rectangles instead.
1824 RenderObject* render = final.mNode->renderer();
1825 IntPoint offset = roundedIntPoint(render->localToAbsolute());
1826 render->absoluteRects(rects, offset.x() + frameAdjust.x(), offset.y() + frameAdjust.y());
1827 bool inside = false;
1828 int distance = INT_MAX;
1829 int newx = x, newy = y;
1830 int i = rects.size();
1832 if (rects[i].isEmpty()) {
1836 // check whether the point (x, y) is inside one of the rectangles.
1839 if (rects[i].contains(x, y)) {
1843 if (x >= rects[i].x() && x < rects[i].maxX()) {
1844 if (y < rects[i].y()) {
1845 if (rects[i].y() - y < distance) {
1847 newy = rects[i].y();
1848 distance = rects[i].y() - y;
1850 } else if (y >= rects[i].maxY()) {
1851 if (y - rects[i].maxY() + 1 < distance) {
1853 newy = rects[i].maxY() - 1;
1854 distance = y - rects[i].maxY() + 1;
1857 } else if (y >= rects[i].y() && y < rects[i].maxY()) {
1858 if (x < rects[i].x()) {
1859 if (rects[i].x() - x < distance) {
1860 newx = rects[i].x();
1862 distance = rects[i].x() - x;
1864 } else if (x >= rects[i].maxX()) {
1865 if (x - rects[i].maxX() + 1 < distance) {
1866 newx = rects[i].maxX() - 1;
1868 distance = x - rects[i].maxX() + 1;
1873 if (!rects.isEmpty()) {
1875 // if neither x nor y has overlap, just pick the top/left of the first rectangle
1876 if (newx == x && newy == y) {
1877 newx = rects[0].x();
1878 newy = rects[0].y();
1880 m_mousePos.setX(newx - m_scrollOffsetX);
1881 m_mousePos.setY(newy - m_scrollOffsetY);
1882 DBG_NAV_LOGD("Move x/y from (%d, %d) to (%d, %d) scrollOffset is (%d, %d)",
1883 x, y, m_mousePos.x() + m_scrollOffsetX, m_mousePos.y() + m_scrollOffsetY,
1884 m_scrollOffsetX, m_scrollOffsetY);
1889 IntRect rect = final.mBounds;
1890 rect.move(frameAdjust.x(), frameAdjust.y());
1892 // adjust m_mousePos if it is not inside the returned highlight rectangle
1893 testRect.move(frameAdjust.x(), frameAdjust.y());
1894 testRect.intersect(rect);
1895 if (!testRect.contains(x, y)) {
1896 m_mousePos = testRect.center();
1897 m_mousePos.move(-m_scrollOffsetX, -m_scrollOffsetY);
1898 DBG_NAV_LOGD("Move x/y from (%d, %d) to (%d, %d) scrollOffset is (%d, %d)",
1899 x, y, m_mousePos.x() + m_scrollOffsetX, m_mousePos.y() + m_scrollOffsetY,
1900 m_scrollOffsetX, m_scrollOffsetY);
1906 ///////////////////////////////////////////////////////////////////////////////
1908 void WebViewCore::addPlugin(PluginWidgetAndroid* w)
1910 // SkDebugf("----------- addPlugin %p", w);
1911 /* The plugin must be appended to the end of the array. This ensures that if
1912 the plugin is added while iterating through the array (e.g. sendEvent(...))
1913 that the iteration process is not corrupted.
1915 *m_plugins.append() = w;
1918 void WebViewCore::removePlugin(PluginWidgetAndroid* w)
1920 // SkDebugf("----------- removePlugin %p", w);
1921 int index = m_plugins.find(w);
1923 SkDebugf("--------------- pluginwindow not found! %p\n", w);
1925 m_plugins.removeShuffle(index);
1929 bool WebViewCore::isPlugin(PluginWidgetAndroid* w) const
1931 return m_plugins.find(w) >= 0;
1934 void WebViewCore::invalPlugin(PluginWidgetAndroid* w)
1936 const double PLUGIN_INVAL_DELAY = 1.0 / 60;
1938 if (!m_pluginInvalTimer.isActive()) {
1939 m_pluginInvalTimer.startOneShot(PLUGIN_INVAL_DELAY);
1943 void WebViewCore::drawPlugins()
1945 SkRegion inval; // accumualte what needs to be redrawn
1946 PluginWidgetAndroid** iter = m_plugins.begin();
1947 PluginWidgetAndroid** stop = m_plugins.end();
1949 for (; iter < stop; ++iter) {
1950 PluginWidgetAndroid* w = *iter;
1952 if (w->isDirty(&dirty)) {
1954 inval.op(dirty, SkRegion::kUnion_Op);
1958 if (!inval.isEmpty()) {
1959 // inval.getBounds() is our rectangle
1960 const SkIRect& bounds = inval.getBounds();
1961 WebCore::IntRect r(bounds.fLeft, bounds.fTop,
1962 bounds.width(), bounds.height());
1963 this->viewInvalidate(r);
1967 void WebViewCore::notifyPluginsOnFrameLoad(const Frame* frame) {
1968 // if frame is the parent then notify all plugins
1969 if (!frame->tree()->parent()) {
1970 // trigger an event notifying the plugins that the page has loaded
1972 SkANP::InitEvent(&event, kLifecycle_ANPEventType);
1973 event.data.lifecycle.action = kOnLoad_ANPLifecycleAction;
1974 sendPluginEvent(event);
1975 // trigger the on/off screen notification if the page was reloaded
1976 sendPluginVisibleScreen();
1978 // else if frame's parent has completed
1979 else if (!frame->tree()->parent()->loader()->isLoading()) {
1980 // send to all plugins who have this frame in their heirarchy
1981 PluginWidgetAndroid** iter = m_plugins.begin();
1982 PluginWidgetAndroid** stop = m_plugins.end();
1983 for (; iter < stop; ++iter) {
1984 Frame* currentFrame = (*iter)->pluginView()->parentFrame();
1985 while (currentFrame) {
1986 if (frame == currentFrame) {
1988 SkANP::InitEvent(&event, kLifecycle_ANPEventType);
1989 event.data.lifecycle.action = kOnLoad_ANPLifecycleAction;
1990 (*iter)->sendEvent(event);
1992 // trigger the on/off screen notification if the page was reloaded
1993 ANPRectI visibleRect;
1994 getVisibleScreen(visibleRect);
1995 (*iter)->setVisibleScreen(visibleRect, m_scale);
1999 currentFrame = currentFrame->tree()->parent();
2005 void WebViewCore::getVisibleScreen(ANPRectI& visibleRect)
2007 visibleRect.left = m_scrollOffsetX;
2008 visibleRect.top = m_scrollOffsetY;
2009 visibleRect.right = m_scrollOffsetX + m_screenWidth;
2010 visibleRect.bottom = m_scrollOffsetY + m_screenHeight;
2013 void WebViewCore::sendPluginVisibleScreen()
2015 /* We may want to cache the previous values and only send the notification
2016 to the plugin in the event that one of the values has changed.
2019 ANPRectI visibleRect;
2020 getVisibleScreen(visibleRect);
2022 PluginWidgetAndroid** iter = m_plugins.begin();
2023 PluginWidgetAndroid** stop = m_plugins.end();
2024 for (; iter < stop; ++iter) {
2025 (*iter)->setVisibleScreen(visibleRect, m_scale);
2029 void WebViewCore::sendPluginSurfaceReady()
2031 PluginWidgetAndroid** iter = m_plugins.begin();
2032 PluginWidgetAndroid** stop = m_plugins.end();
2033 for (; iter < stop; ++iter) {
2034 (*iter)->checkSurfaceReady();
2038 void WebViewCore::sendPluginEvent(const ANPEvent& evt)
2040 /* The list of plugins may be manipulated as we iterate through the list.
2041 This implementation allows for the addition of new plugins during an
2042 iteration, but may fail if a plugin is removed. Currently, there are not
2043 any use cases where a plugin is deleted while processing this loop, but
2044 if it does occur we will have to use an alternate data structure and/or
2045 iteration mechanism.
2047 for (int x = 0; x < m_plugins.count(); x++) {
2048 m_plugins[x]->sendEvent(evt);
2052 PluginWidgetAndroid* WebViewCore::getPluginWidget(NPP npp)
2054 PluginWidgetAndroid** iter = m_plugins.begin();
2055 PluginWidgetAndroid** stop = m_plugins.end();
2056 for (; iter < stop; ++iter) {
2057 if ((*iter)->pluginView()->instance() == npp) {
2064 static PluginView* nodeIsPlugin(Node* node) {
2065 RenderObject* renderer = node->renderer();
2066 if (renderer && renderer->isWidget()) {
2067 Widget* widget = static_cast<RenderWidget*>(renderer)->widget();
2068 if (widget && widget->isPluginView())
2069 return static_cast<PluginView*>(widget);
2074 Node* WebViewCore::cursorNodeIsPlugin() {
2075 gCursorBoundsMutex.lock();
2076 bool hasCursorBounds = m_hasCursorBounds;
2077 Frame* frame = (Frame*) m_cursorFrame;
2078 Node* node = (Node*) m_cursorNode;
2079 gCursorBoundsMutex.unlock();
2080 if (hasCursorBounds && CacheBuilder::validNode(m_mainFrame, frame, node)
2081 && nodeIsPlugin(node)) {
2087 ///////////////////////////////////////////////////////////////////////////////
2088 void WebViewCore::moveMouseIfLatest(int moveGeneration,
2089 WebCore::Frame* frame, int x, int y)
2091 DBG_NAV_LOGD("m_moveGeneration=%d moveGeneration=%d"
2092 " frame=%p x=%d y=%d",
2093 m_moveGeneration, moveGeneration, frame, x, y);
2094 if (m_moveGeneration > moveGeneration) {
2095 DBG_NAV_LOGD("m_moveGeneration=%d > moveGeneration=%d",
2096 m_moveGeneration, moveGeneration);
2097 return; // short-circuit if a newer move has already been generated
2099 m_lastGeneration = moveGeneration;
2100 moveMouse(frame, x, y);
2103 void WebViewCore::moveFocus(WebCore::Frame* frame, WebCore::Node* node)
2105 DBG_NAV_LOGD("frame=%p node=%p", frame, node);
2106 if (!node || !CacheBuilder::validNode(m_mainFrame, frame, node)
2107 || !node->isElementNode())
2109 // Code borrowed from FocusController::advanceFocus
2110 WebCore::FocusController* focusController
2111 = m_mainFrame->page()->focusController();
2112 WebCore::Document* oldDoc
2113 = focusController->focusedOrMainFrame()->document();
2114 if (oldDoc->focusedNode() == node)
2116 if (node->document() != oldDoc)
2117 oldDoc->setFocusedNode(0);
2118 focusController->setFocusedFrame(frame);
2119 static_cast<WebCore::Element*>(node)->focus(false);
2122 // Update mouse position
2123 void WebViewCore::moveMouse(WebCore::Frame* frame, int x, int y)
2125 DBG_NAV_LOGD("frame=%p x=%d y=%d scrollOffset=(%d,%d)", frame,
2126 x, y, m_scrollOffsetX, m_scrollOffsetY);
2127 if (!frame || !CacheBuilder::validNode(m_mainFrame, frame, 0))
2128 frame = m_mainFrame;
2129 // mouse event expects the position in the window coordinate
2130 m_mousePos = WebCore::IntPoint(x - m_scrollOffsetX, y - m_scrollOffsetY);
2131 // validNode will still return true if the node is null, as long as we have
2132 // a valid frame. Do not want to make a call on frame unless it is valid.
2133 WebCore::PlatformMouseEvent mouseEvent(m_mousePos, m_mousePos,
2134 WebCore::NoButton, WebCore::MouseEventMoved, 1, false, false, false,
2135 false, WTF::currentTime());
2136 frame->eventHandler()->handleMouseMoveEvent(mouseEvent);
2137 updateCacheOnNodeChange();
2140 void WebViewCore::setSelection(int start, int end)
2142 WebCore::Node* focus = currentFocus();
2145 WebCore::RenderObject* renderer = focus->renderer();
2146 if (!renderer || (!renderer->isTextField() && !renderer->isTextArea()))
2153 // Tell our EditorClient that this change was generated from the UI, so it
2154 // does not need to echo it to the UI.
2155 EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
2156 m_mainFrame->editor()->client());
2157 client->setUiGeneratedSelectionChange(true);
2158 setSelectionRange(focus, start, end);
2160 // Fire a select event. No event is sent when the selection reduces to
2161 // an insertion point
2162 RenderTextControl* control = toRenderTextControl(renderer);
2163 control->selectionChanged(true);
2165 client->setUiGeneratedSelectionChange(false);
2166 WebCore::Frame* focusedFrame = focus->document()->frame();
2167 bool isPasswordField = false;
2168 if (focus->isElementNode()) {
2169 WebCore::Element* element = static_cast<WebCore::Element*>(focus);
2170 if (WebCore::InputElement* inputElement = element->toInputElement())
2171 isPasswordField = static_cast<WebCore::HTMLInputElement*>(inputElement)->isPasswordField();
2173 // For password fields, this is done in the UI side via
2174 // bringPointIntoView, since the UI does the drawing.
2175 if (renderer->isTextArea() || !isPasswordField)
2179 String WebViewCore::modifySelection(const int direction, const int axis)
2181 DOMSelection* selection = m_mainFrame->domWindow()->getSelection();
2183 // We've seen crashes where selection is null, but we don't know why
2184 // See http://b/5244036
2187 if (selection->rangeCount() > 1)
2188 selection->removeAllRanges();
2190 case AXIS_CHARACTER:
2193 return modifySelectionTextNavigationAxis(selection, direction, axis);
2196 case AXIS_PARENT_FIRST_CHILD:
2198 return modifySelectionDomNavigationAxis(selection, direction, axis);
2200 LOGE("Invalid navigation axis: %d", axis);
2205 void WebViewCore::scrollNodeIntoView(Frame* frame, Node* node)
2207 if (!frame || !node)
2210 Element* elementNode = 0;
2212 // If not an Element, find a visible predecessor
2213 // Element to scroll into view.
2214 if (!node->isElementNode()) {
2215 HTMLElement* body = frame->document()->body();
2219 node = node->parentNode();
2220 } while (node && !node->isElementNode() && !isVisible(node));
2223 // Couldn't find a visible predecessor.
2227 elementNode = static_cast<Element*>(node);
2228 elementNode->scrollIntoViewIfNeeded(true);
2231 String WebViewCore::modifySelectionTextNavigationAxis(DOMSelection* selection, int direction, int axis)
2233 Node* body = m_mainFrame->document()->body();
2235 ExceptionCode ec = 0;
2238 // initialize the selection if necessary
2239 if (selection->rangeCount() == 0) {
2240 if (m_currentNodeDomNavigationAxis
2241 && CacheBuilder::validNode(m_mainFrame,
2242 m_mainFrame, m_currentNodeDomNavigationAxis)) {
2243 PassRefPtr<Range> rangeRef =
2244 selection->frame()->document()->createRange();
2245 rangeRef->selectNode(m_currentNodeDomNavigationAxis, ec);
2246 m_currentNodeDomNavigationAxis = 0;
2249 selection->addRange(rangeRef.get());
2250 } else if (currentFocus()) {
2251 selection->setPosition(currentFocus(), 0, ec);
2252 } else if (m_cursorNode
2253 && CacheBuilder::validNode(m_mainFrame,
2254 m_mainFrame, m_cursorNode)) {
2255 PassRefPtr<Range> rangeRef =
2256 selection->frame()->document()->createRange();
2257 rangeRef->selectNode(reinterpret_cast<Node*>(m_cursorNode), ec);
2260 selection->addRange(rangeRef.get());
2262 selection->setPosition(body, 0, ec);
2268 // collapse the selection
2269 if (direction == DIRECTION_FORWARD)
2270 selection->collapseToEnd(ec);
2272 selection->collapseToStart(ec);
2276 // Make sure the anchor node is a text node since we are generating
2277 // the markup of the selection which includes the anchor, the focus,
2278 // and any crossed nodes. Forcing the condition that the selection
2279 // starts and ends on text nodes guarantees symmetric selection markup.
2280 // Also this way the text content, rather its container, is highlighted.
2281 Node* anchorNode = selection->anchorNode();
2282 if (anchorNode->isElementNode()) {
2283 // Collapsed selection while moving forward points to the
2284 // next unvisited node and while moving backward to the
2285 // last visited node.
2286 if (direction == DIRECTION_FORWARD)
2287 advanceAnchorNode(selection, direction, markup, false, ec);
2289 advanceAnchorNode(selection, direction, markup, true, ec);
2292 if (!markup.isEmpty())
2296 // If the selection is at the end of a non white space text move
2297 // it to the next visible text node with non white space content.
2298 // This is a workaround for the selection getting stuck.
2299 anchorNode = selection->anchorNode();
2300 if (anchorNode->isTextNode()) {
2301 if (direction == DIRECTION_FORWARD) {
2302 String suffix = anchorNode->textContent().substring(
2303 selection->anchorOffset(), caretMaxOffset(anchorNode));
2304 // If at the end of non white space text we advance the
2305 // anchor node to either an input element or non empty text.
2306 if (suffix.stripWhiteSpace().isEmpty()) {
2307 advanceAnchorNode(selection, direction, markup, true, ec);
2310 String prefix = anchorNode->textContent().substring(0,
2311 selection->anchorOffset());
2312 // If at the end of non white space text we advance the
2313 // anchor node to either an input element or non empty text.
2314 if (prefix.stripWhiteSpace().isEmpty()) {
2315 advanceAnchorNode(selection, direction, markup, true, ec);
2320 if (!markup.isEmpty())
2324 // extend the selection
2325 String directionStr;
2326 if (direction == DIRECTION_FORWARD)
2327 directionStr = "forward";
2329 directionStr = "backward";
2332 if (axis == AXIS_CHARACTER)
2333 axisStr = "character";
2334 else if (axis == AXIS_WORD)
2337 axisStr = "sentence";
2339 selection->modify("extend", directionStr, axisStr);
2341 // Make sure the focus node is a text node in order to have the
2342 // selection generate symmetric markup because the latter
2343 // includes all nodes crossed by the selection. Also this way
2344 // the text content, rather its container, is highlighted.
2345 Node* focusNode = selection->focusNode();
2346 if (focusNode->isElementNode()) {
2347 focusNode = getImplicitBoundaryNode(selection->focusNode(),
2348 selection->focusOffset(), direction);
2351 if (direction == DIRECTION_FORWARD) {
2352 focusNode = focusNode->traversePreviousSiblingPostOrder(body);
2353 if (focusNode && !isContentTextNode(focusNode)) {
2354 Node* textNode = traverseNextContentTextNode(focusNode,
2355 anchorNode, DIRECTION_BACKWARD);
2357 anchorNode = textNode;
2359 if (focusNode && isContentTextNode(focusNode)) {
2360 selection->extend(focusNode, caretMaxOffset(focusNode), ec);
2365 focusNode = focusNode->traverseNextSibling();
2366 if (focusNode && !isContentTextNode(focusNode)) {
2367 Node* textNode = traverseNextContentTextNode(focusNode,
2368 anchorNode, DIRECTION_FORWARD);
2370 anchorNode = textNode;
2372 if (anchorNode && isContentTextNode(anchorNode)) {
2373 selection->extend(focusNode, 0, ec);
2380 // Enforce that the selection does not cross anchor boundaries. This is
2381 // a workaround for the asymmetric behavior of WebKit while crossing
2383 anchorNode = getImplicitBoundaryNode(selection->anchorNode(),
2384 selection->anchorOffset(), direction);
2385 focusNode = getImplicitBoundaryNode(selection->focusNode(),
2386 selection->focusOffset(), direction);
2387 if (anchorNode && focusNode && anchorNode != focusNode) {
2388 Node* inputControl = getIntermediaryInputElement(anchorNode, focusNode,
2391 if (direction == DIRECTION_FORWARD) {
2392 if (isDescendantOf(inputControl, anchorNode)) {
2393 focusNode = inputControl;
2395 focusNode = inputControl->traversePreviousSiblingPostOrder(
2398 focusNode = inputControl;
2400 // We prefer a text node contained in the input element.
2401 if (!isContentTextNode(focusNode)) {
2402 Node* textNode = traverseNextContentTextNode(focusNode,
2403 anchorNode, DIRECTION_BACKWARD);
2405 focusNode = textNode;
2407 // If we found text in the input select it.
2408 // Otherwise, select the input element itself.
2409 if (isContentTextNode(focusNode)) {
2410 selection->extend(focusNode, caretMaxOffset(focusNode), ec);
2411 } else if (anchorNode != focusNode) {
2412 // Note that the focusNode always has parent and that
2413 // the offset can be one more that the index of the last
2414 // element - this is how WebKit selects such elements.
2415 selection->extend(focusNode->parentNode(),
2416 focusNode->nodeIndex() + 1, ec);
2421 if (isDescendantOf(inputControl, anchorNode)) {
2422 focusNode = inputControl;
2424 focusNode = inputControl->traverseNextSibling();
2426 focusNode = inputControl;
2428 // We prefer a text node contained in the input element.
2429 if (!isContentTextNode(focusNode)) {
2430 Node* textNode = traverseNextContentTextNode(focusNode,
2431 anchorNode, DIRECTION_FORWARD);
2433 focusNode = textNode;
2435 // If we found text in the input select it.
2436 // Otherwise, select the input element itself.
2437 if (isContentTextNode(focusNode)) {
2438 selection->extend(focusNode, caretMinOffset(focusNode), ec);
2439 } else if (anchorNode != focusNode) {
2440 // Note that the focusNode always has parent and that
2441 // the offset can be one more that the index of the last
2442 // element - this is how WebKit selects such elements.
2443 selection->extend(focusNode->parentNode(),
2444 focusNode->nodeIndex() + 1, ec);
2452 // make sure the selection is visible
2453 if (direction == DIRECTION_FORWARD)
2454 scrollNodeIntoView(m_mainFrame, selection->focusNode());
2456 scrollNodeIntoView(m_mainFrame, selection->anchorNode());
2458 // format markup for the visible content
2459 PassRefPtr<Range> range = selection->getRangeAt(0, ec);
2462 IntRect bounds = range->boundingBox();
2463 selectAt(bounds.center().x(), bounds.center().y());
2464 markup = formatMarkup(selection);
2465 LOGV("Selection markup: %s", markup.utf8().data());
2470 Node* WebViewCore::getImplicitBoundaryNode(Node* node, unsigned offset, int direction)
2472 if (node->offsetInCharacters())
2474 if (!node->hasChildNodes())
2476 if (offset < node->childNodeCount())
2477 return node->childNode(offset);
2479 if (direction == DIRECTION_FORWARD)
2480 return node->traverseNextSibling();
2482 return node->traversePreviousNodePostOrder(
2483 node->document()->body());
2486 Node* WebViewCore::getNextAnchorNode(Node* anchorNode, bool ignoreFirstNode, int direction)
2489 Node* currentNode = 0;
2490 if (direction == DIRECTION_FORWARD) {
2491 if (ignoreFirstNode)
2492 currentNode = anchorNode->traverseNextNode(body);
2494 currentNode = anchorNode;
2496 body = anchorNode->document()->body();
2497 if (ignoreFirstNode)
2498 currentNode = anchorNode->traversePreviousSiblingPostOrder(body);
2500 currentNode = anchorNode;
2502 while (currentNode) {
2503 if (isContentTextNode(currentNode)
2504 || isContentInputElement(currentNode))
2506 if (direction == DIRECTION_FORWARD)
2507 currentNode = currentNode->traverseNextNode();
2509 currentNode = currentNode->traversePreviousNodePostOrder(body);
2514 void WebViewCore::advanceAnchorNode(DOMSelection* selection, int direction,
2515 String& markup, bool ignoreFirstNode, ExceptionCode& ec)
2517 Node* anchorNode = getImplicitBoundaryNode(selection->anchorNode(),
2518 selection->anchorOffset(), direction);
2523 // If the anchor offset is invalid i.e. the anchor node has no
2524 // child with that index getImplicitAnchorNode returns the next
2525 // logical node in the current direction. In such a case our
2526 // position in the DOM tree was has already been advanced,
2527 // therefore we there is no need to do that again.
2528 if (selection->anchorNode()->isElementNode()) {
2529 unsigned anchorOffset = selection->anchorOffset();
2530 unsigned childNodeCount = selection->anchorNode()->childNodeCount();
2531 if (anchorOffset >= childNodeCount)
2532 ignoreFirstNode = false;
2534 // Find the next anchor node given our position in the DOM and
2535 // whether we want the current node to be considered as well.
2536 Node* nextAnchorNode = getNextAnchorNode(anchorNode, ignoreFirstNode,
2538 if (!nextAnchorNode) {
2542 if (nextAnchorNode->isElementNode()) {
2543 // If this is an input element tell the WebView thread
2544 // to set the cursor to that control.
2545 if (isContentInputElement(nextAnchorNode)) {
2546 IntRect bounds = nextAnchorNode->getRect();
2547 selectAt(bounds.center().x(), bounds.center().y());
2550 // Treat the text content of links as any other text but
2551 // for the rest input elements select the control itself.
2552 if (nextAnchorNode->hasTagName(WebCore::HTMLNames::aTag))
2553 textNode = traverseNextContentTextNode(nextAnchorNode,
2554 nextAnchorNode, direction);
2555 // We prefer to select the text content of the link if such,
2556 // otherwise just select the element itself.
2558 nextAnchorNode = textNode;
2560 if (direction == DIRECTION_FORWARD) {
2561 selection->setBaseAndExtent(nextAnchorNode,
2562 caretMinOffset(nextAnchorNode), nextAnchorNode,
2563 caretMaxOffset(nextAnchorNode), ec);
2565 selection->setBaseAndExtent(nextAnchorNode,
2566 caretMaxOffset(nextAnchorNode), nextAnchorNode,
2567 caretMinOffset(nextAnchorNode), ec);
2570 markup = formatMarkup(selection);
2571 // make sure the selection is visible
2572 scrollNodeIntoView(selection->frame(), nextAnchorNode);
2576 if (direction == DIRECTION_FORWARD)
2577 selection->setPosition(nextAnchorNode,
2578 caretMinOffset(nextAnchorNode), ec);
2580 selection->setPosition(nextAnchorNode,
2581 caretMaxOffset(nextAnchorNode), ec);
2584 bool WebViewCore::isContentInputElement(Node* node)
2586 return (isVisible(node)
2587 && (node->hasTagName(WebCore::HTMLNames::selectTag)
2588 || node->hasTagName(WebCore::HTMLNames::aTag)
2589 || node->hasTagName(WebCore::HTMLNames::inputTag)
2590 || node->hasTagName(WebCore::HTMLNames::buttonTag)));
2593 bool WebViewCore::isContentTextNode(Node* node)
2595 if (!node || !node->isTextNode())
2597 Text* textNode = static_cast<Text*>(node);
2598 return (isVisible(textNode) && textNode->length() > 0
2599 && !textNode->containsOnlyWhitespace());
2602 Text* WebViewCore::traverseNextContentTextNode(Node* fromNode, Node* toNode, int direction)
2604 Node* currentNode = fromNode;
2606 if (direction == DIRECTION_FORWARD)
2607 currentNode = currentNode->traverseNextNode(toNode);
2609 currentNode = currentNode->traversePreviousNodePostOrder(toNode);
2610 } while (currentNode && !isContentTextNode(currentNode));
2611 return static_cast<Text*>(currentNode);
2614 Node* WebViewCore::getIntermediaryInputElement(Node* fromNode, Node* toNode, int direction)
2616 if (fromNode == toNode)
2618 if (direction == DIRECTION_FORWARD) {
2619 Node* currentNode = fromNode;
2620 while (currentNode && currentNode != toNode) {
2621 if (isContentInputElement(currentNode))
2623 currentNode = currentNode->traverseNextNodePostOrder();
2625 currentNode = fromNode;
2626 while (currentNode && currentNode != toNode) {
2627 if (isContentInputElement(currentNode))
2629 currentNode = currentNode->traverseNextNode();
2632 Node* currentNode = fromNode->traversePreviousNode();
2633 while (currentNode && currentNode != toNode) {
2634 if (isContentInputElement(currentNode))
2636 currentNode = currentNode->traversePreviousNode();
2638 currentNode = fromNode->traversePreviousNodePostOrder();
2639 while (currentNode && currentNode != toNode) {
2640 if (isContentInputElement(currentNode))
2642 currentNode = currentNode->traversePreviousNodePostOrder();
2648 bool WebViewCore::isDescendantOf(Node* parent, Node* node)
2650 Node* currentNode = node;
2651 while (currentNode) {
2652 if (currentNode == parent) {
2655 currentNode = currentNode->parentNode();
2660 String WebViewCore::modifySelectionDomNavigationAxis(DOMSelection* selection, int direction, int axis)
2662 HTMLElement* body = m_mainFrame->document()->body();
2663 if (!m_currentNodeDomNavigationAxis && selection->focusNode()) {
2664 m_currentNodeDomNavigationAxis = selection->focusNode();
2666 if (m_currentNodeDomNavigationAxis->isTextNode())
2667 m_currentNodeDomNavigationAxis =
2668 m_currentNodeDomNavigationAxis->parentNode();
2670 if (!m_currentNodeDomNavigationAxis)
2671 m_currentNodeDomNavigationAxis = currentFocus();
2672 if (!m_currentNodeDomNavigationAxis
2673 || !CacheBuilder::validNode(m_mainFrame, m_mainFrame,
2674 m_currentNodeDomNavigationAxis))
2675 m_currentNodeDomNavigationAxis = body;
2676 Node* currentNode = m_currentNodeDomNavigationAxis;
2677 if (axis == AXIS_HEADING) {
2678 if (currentNode == body && direction == DIRECTION_BACKWARD)
2679 currentNode = currentNode->lastDescendant();
2681 if (direction == DIRECTION_FORWARD)
2682 currentNode = currentNode->traverseNextNode(body);
2684 currentNode = currentNode->traversePreviousNode(body);
2685 } while (currentNode && (currentNode->isTextNode()
2686 || !isVisible(currentNode) || !isHeading(currentNode)));
2687 } else if (axis == AXIS_PARENT_FIRST_CHILD) {
2688 if (direction == DIRECTION_FORWARD) {
2689 currentNode = currentNode->firstChild();
2690 while (currentNode && (currentNode->isTextNode()
2691 || !isVisible(currentNode)))
2692 currentNode = currentNode->nextSibling();
2695 if (currentNode == body)
2697 currentNode = currentNode->parentNode();
2698 } while (currentNode && (currentNode->isTextNode()
2699 || !isVisible(currentNode)));
2701 } else if (axis == AXIS_SIBLING) {
2703 if (direction == DIRECTION_FORWARD)
2704 currentNode = currentNode->nextSibling();
2706 if (currentNode == body)
2708 currentNode = currentNode->previousSibling();
2710 } while (currentNode && (currentNode->isTextNode()
2711 || !isVisible(currentNode)));
2712 } else if (axis == AXIS_DOCUMENT) {
2714 if (direction == DIRECTION_FORWARD)
2715 currentNode = currentNode->lastDescendant();
2717 LOGE("Invalid axis: %d", axis);
2721 m_currentNodeDomNavigationAxis = currentNode;
2722 scrollNodeIntoView(m_mainFrame, currentNode);
2723 String selectionString = createMarkup(currentNode);
2724 LOGV("Selection markup: %s", selectionString.utf8().data());
2725 return selectionString;
2730 bool WebViewCore::isHeading(Node* node)
2732 if (node->hasTagName(WebCore::HTMLNames::h1Tag)
2733 || node->hasTagName(WebCore::HTMLNames::h2Tag)
2734 || node->hasTagName(WebCore::HTMLNames::h3Tag)
2735 || node->hasTagName(WebCore::HTMLNames::h4Tag)
2736 || node->hasTagName(WebCore::HTMLNames::h5Tag)
2737 || node->hasTagName(WebCore::HTMLNames::h6Tag)) {
2741 if (node->isElementNode()) {
2742 Element* element = static_cast<Element*>(node);
2743 String roleAttribute =
2744 element->getAttribute(WebCore::HTMLNames::roleAttr).string();
2745 if (equalIgnoringCase(roleAttribute, "heading"))
2752 bool WebViewCore::isVisible(Node* node)
2754 // start off an element
2755 Element* element = 0;
2756 if (node->isElementNode())
2757 element = static_cast<Element*>(node);
2759 element = node->parentElement();
2761 if (!element->renderer()) {
2765 if (element->offsetHeight() == 0 || element->offsetWidth() == 0) {
2769 Node* body = m_mainFrame->document()->body();
2770 Node* currentNode = element;
2771 while (currentNode && currentNode != body) {
2772 RenderStyle* style = currentNode->computedStyle();
2774 (style->display() == NONE || style->visibility() == HIDDEN)) {
2777 currentNode = currentNode->parentNode();
2782 String WebViewCore::formatMarkup(DOMSelection* selection)
2784 ExceptionCode ec = 0;
2785 String markup = String();
2786 PassRefPtr<Range> wholeRange = selection->getRangeAt(0, ec);
2789 if (!wholeRange->startContainer() || !wholeRange->startContainer())
2791 // Since formatted markup contains invisible nodes it
2792 // is created from the concatenation of the visible fragments.
2793 Node* firstNode = wholeRange->firstNode();
2794 Node* pastLastNode = wholeRange->pastLastNode();
2795 Node* currentNode = firstNode;
2796 PassRefPtr<Range> currentRange;
2798 while (currentNode != pastLastNode) {
2799 Node* nextNode = currentNode->traverseNextNode();
2800 if (!isVisible(currentNode)) {
2802 markup = markup + currentRange->toHTML().utf8().data();
2806 if (!currentRange) {
2807 currentRange = selection->frame()->document()->createRange();
2810 if (currentNode == firstNode) {
2811 currentRange->setStart(wholeRange->startContainer(),
2812 wholeRange->startOffset(), ec);
2816 currentRange->setStart(currentNode->parentNode(),
2817 currentNode->nodeIndex(), ec);
2822 if (nextNode == pastLastNode) {
2823 currentRange->setEnd(wholeRange->endContainer(),
2824 wholeRange->endOffset(), ec);
2827 markup = markup + currentRange->toHTML().utf8().data();
2829 if (currentNode->offsetInCharacters())
2830 currentRange->setEnd(currentNode,
2831 currentNode->maxCharacterOffset(), ec);
2833 currentRange->setEnd(currentNode->parentNode(),
2834 currentNode->nodeIndex() + 1, ec);
2839 currentNode = nextNode;
2841 return markup.stripWhiteSpace();
2844 void WebViewCore::selectAt(int x, int y)
2846 JNIEnv* env = JSC::Bindings::getJNIEnv();
2847 AutoJObject javaObject = m_javaGlue->object(env);
2848 if (!javaObject.get())
2850 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_selectAt, x, y);
2851 checkException(env);
2854 void WebViewCore::deleteSelection(int start, int end, int textGeneration)
2856 setSelection(start, end);
2859 WebCore::Node* focus = currentFocus();
2862 // Prevent our editor client from passing a message to change the
2864 EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
2865 m_mainFrame->editor()->client());
2866 client->setUiGeneratedSelectionChange(true);
2867 PlatformKeyboardEvent down(AKEYCODE_DEL, 0, 0, true, false, false, false);
2868 PlatformKeyboardEvent up(AKEYCODE_DEL, 0, 0, false, false, false, false);
2871 client->setUiGeneratedSelectionChange(false);
2872 m_textGeneration = textGeneration;
2873 m_shouldPaintCaret = true;
2876 void WebViewCore::replaceTextfieldText(int oldStart,
2877 int oldEnd, const WTF::String& replace, int start, int end,
2880 WebCore::Node* focus = currentFocus();
2883 setSelection(oldStart, oldEnd);
2884 // Prevent our editor client from passing a message to change the
2886 EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
2887 m_mainFrame->editor()->client());
2888 client->setUiGeneratedSelectionChange(true);
2889 WebCore::TypingCommand::insertText(focus->document(), replace,
2891 client->setUiGeneratedSelectionChange(false);
2892 // setSelection calls revealSelection, so there is no need to do it here.
2893 setSelection(start, end);
2894 m_textGeneration = textGeneration;
2895 m_shouldPaintCaret = true;
2898 void WebViewCore::passToJs(int generation, const WTF::String& current,
2899 const PlatformKeyboardEvent& event)
2901 WebCore::Node* focus = currentFocus();
2903 DBG_NAV_LOG("!focus");
2907 WebCore::RenderObject* renderer = focus->renderer();
2908 if (!renderer || (!renderer->isTextField() && !renderer->isTextArea())) {
2909 DBG_NAV_LOGD("renderer==%p || not text", renderer);
2913 // Block text field updates during a key press.
2914 m_blockTextfieldUpdates = true;
2915 // Also prevent our editor client from passing a message to change the
2917 EditorClientAndroid* client = static_cast<EditorClientAndroid*>(
2918 m_mainFrame->editor()->client());
2919 client->setUiGeneratedSelectionChange(true);
2921 client->setUiGeneratedSelectionChange(false);
2922 m_blockTextfieldUpdates = false;
2923 m_textGeneration = generation;
2924 WebCore::RenderTextControl* renderText =
2925 static_cast<WebCore::RenderTextControl*>(renderer);
2926 WTF::String test = renderText->text();
2927 if (test != current) {
2928 // If the text changed during the key event, update the UI text field.
2929 updateTextfield(focus, false, test);
2931 DBG_NAV_LOG("test == current");
2933 // Now that the selection has settled down, send it.
2934 updateTextSelection();
2935 m_shouldPaintCaret = true;
2938 void WebViewCore::scrollFocusedTextInput(float xPercent, int y)
2940 WebCore::Node* focus = currentFocus();
2942 DBG_NAV_LOG("!focus");
2946 WebCore::RenderObject* renderer = focus->renderer();
2947 if (!renderer || (!renderer->isTextField() && !renderer->isTextArea())) {
2948 DBG_NAV_LOGD("renderer==%p || not text", renderer);
2952 WebCore::RenderTextControl* renderText =
2953 static_cast<WebCore::RenderTextControl*>(renderer);
2954 int x = (int) (xPercent * (renderText->scrollWidth() -
2955 renderText->clientWidth()));
2956 DBG_NAV_LOGD("x=%d y=%d xPercent=%g scrollW=%d clientW=%d", x, y,
2957 xPercent, renderText->scrollWidth(), renderText->clientWidth());
2958 renderText->setScrollLeft(x);
2959 renderText->setScrollTop(y);
2962 void WebViewCore::setFocusControllerActive(bool active)
2964 m_mainFrame->page()->focusController()->setActive(active);
2967 void WebViewCore::saveDocumentState(WebCore::Frame* frame)
2969 if (!CacheBuilder::validNode(m_mainFrame, frame, 0))
2970 frame = m_mainFrame;
2971 WebCore::HistoryItem *item = frame->loader()->history()->currentItem();
2973 // item can be null when there is no offical URL for the current page. This happens
2974 // when the content is loaded using with WebCoreFrameBridge::LoadData() and there
2975 // is no failing URL (common case is when content is loaded using data: scheme)
2977 item->setDocumentState(frame->document()->formElementsState());
2981 // Create an array of java Strings.
2982 static jobjectArray makeLabelArray(JNIEnv* env, const uint16_t** labels, size_t count)
2984 jclass stringClass = env->FindClass("java/lang/String");
2985 LOG_ASSERT(stringClass, "Could not find java/lang/String");
2986 jobjectArray array = env->NewObjectArray(count, stringClass, 0);
2987 LOG_ASSERT(array, "Could not create new string array");
2989 for (size_t i = 0; i < count; i++) {
2990 jobject newString = env->NewString(&labels[i][1], labels[i][0]);
2991 env->SetObjectArrayElement(array, i, newString);
2992 env->DeleteLocalRef(newString);
2993 checkException(env);
2995 env->DeleteLocalRef(stringClass);
2999 void WebViewCore::openFileChooser(PassRefPtr<WebCore::FileChooser> chooser)
3001 JNIEnv* env = JSC::Bindings::getJNIEnv();
3002 AutoJObject javaObject = m_javaGlue->object(env);
3003 if (!javaObject.get())
3009 WTF::String acceptType = chooser->acceptTypes();
3010 jstring jAcceptType = wtfStringToJstring(env, acceptType, true);
3011 jstring jName = (jstring) env->CallObjectMethod(
3012 javaObject.get(), m_javaGlue->m_openFileChooser, jAcceptType);
3013 checkException(env);
3014 env->DeleteLocalRef(jAcceptType);
3016 WTF::String wtfString = jstringToWtfString(env, jName);
3017 env->DeleteLocalRef(jName);
3019 if (!wtfString.isEmpty())
3020 chooser->chooseFile(wtfString);
3023 void WebViewCore::listBoxRequest(WebCoreReply* reply, const uint16_t** labels, size_t count, const int enabled[], size_t enabledCount,
3024 bool multiple, const int selected[], size_t selectedCountOrSelection)
3026 LOG_ASSERT(m_javaGlue->m_obj, "No java widget associated with this view!");
3028 JNIEnv* env = JSC::Bindings::getJNIEnv();
3029 AutoJObject javaObject = m_javaGlue->object(env);
3030 if (!javaObject.get())
3033 // If m_popupReply is not null, then we already have a list showing.
3034 if (m_popupReply != 0)
3037 // Create an array of java Strings for the drop down.
3038 jobjectArray labelArray = makeLabelArray(env, labels, count);
3040 // Create an array determining whether each item is enabled.
3041 jintArray enabledArray = env->NewIntArray(enabledCount);
3042 checkException(env);
3043 jint* ptrArray = env->GetIntArrayElements(enabledArray, 0);
3044 checkException(env);
3045 for (size_t i = 0; i < enabledCount; i++) {
3046 ptrArray[i] = enabled[i];
3048 env->ReleaseIntArrayElements(enabledArray, ptrArray, 0);
3049 checkException(env);
3052 // Pass up an array representing which items are selected.
3053 jintArray selectedArray = env->NewIntArray(selectedCountOrSelection);
3054 checkException(env);
3055 jint* selArray = env->GetIntArrayElements(selectedArray, 0);
3056 checkException(env);
3057 for (size_t i = 0; i < selectedCountOrSelection; i++) {
3058 selArray[i] = selected[i];
3060 env->ReleaseIntArrayElements(selectedArray, selArray, 0);
3062 env->CallVoidMethod(javaObject.get(),
3063 m_javaGlue->m_requestListBox, labelArray, enabledArray,
3065 env->DeleteLocalRef(selectedArray);
3067 // Pass up the single selection.
3068 env->CallVoidMethod(javaObject.get(),
3069 m_javaGlue->m_requestSingleListBox, labelArray, enabledArray,
3070 selectedCountOrSelection);
3073 env->DeleteLocalRef(labelArray);
3074 env->DeleteLocalRef(enabledArray);
3075 checkException(env);
3078 m_popupReply = reply;
3081 bool WebViewCore::key(const PlatformKeyboardEvent& event)
3083 WebCore::EventHandler* eventHandler;
3084 WebCore::Node* focusNode = currentFocus();
3085 DBG_NAV_LOGD("keyCode=%s unichar=%d focusNode=%p",
3086 event.keyIdentifier().utf8().data(), event.unichar(), focusNode);
3088 WebCore::Frame* frame = focusNode->document()->frame();
3089 WebFrame* webFrame = WebFrame::getWebFrame(frame);
3090 eventHandler = frame->eventHandler();
3091 VisibleSelection old = frame->selection()->selection();
3092 bool handled = eventHandler->keyEvent(event);
3093 if (isContentEditable(focusNode)) {
3094 // keyEvent will return true even if the contentEditable did not
3095 // change its selection. In the case that it does not, we want to
3096 // return false so that the key will be sent back to our navigation
3098 handled |= frame->selection()->selection() != old;
3102 eventHandler = m_mainFrame->eventHandler();
3104 return eventHandler->keyEvent(event);
3107 // For when the user clicks the trackball, presses dpad center, or types into an
3108 // unfocused textfield. In the latter case, 'fake' will be true
3109 void WebViewCore::click(WebCore::Frame* frame, WebCore::Node* node, bool fake) {
3111 WebCore::IntPoint pt = m_mousePos;
3112 pt.move(m_scrollOffsetX, m_scrollOffsetY);
3113 WebCore::HitTestResult hitTestResult = m_mainFrame->eventHandler()->
3114 hitTestResultAtPoint(pt, false);
3115 node = hitTestResult.innerNode();
3116 frame = node->document()->frame();
3117 DBG_NAV_LOGD("m_mousePos=(%d,%d) m_scrollOffset=(%d,%d) pt=(%d,%d)"
3118 " node=%p", m_mousePos.x(), m_mousePos.y(),
3119 m_scrollOffsetX, m_scrollOffsetY, pt.x(), pt.y(), node);
3122 EditorClientAndroid* client
3123 = static_cast<EditorClientAndroid*>(
3124 m_mainFrame->editor()->client());
3125 client->setShouldChangeSelectedRange(false);
3126 handleMouseClick(frame, node, fake);
3127 client->setShouldChangeSelectedRange(true);
3131 #if USE(ACCELERATED_COMPOSITING)
3132 GraphicsLayerAndroid* WebViewCore::graphicsRootLayer() const
3134 RenderView* contentRenderer = m_mainFrame->contentRenderer();
3135 if (!contentRenderer)
3137 return static_cast<GraphicsLayerAndroid*>(
3138 contentRenderer->compositor()->rootPlatformLayer());
3142 bool WebViewCore::handleTouchEvent(int action, Vector<int>& ids, Vector<IntPoint>& points, int actionIndex, int metaState)
3144 bool preventDefault = false;
3146 #if USE(ACCELERATED_COMPOSITING)
3147 GraphicsLayerAndroid* rootLayer = graphicsRootLayer();
3149 rootLayer->pauseDisplay(true);
3152 #if ENABLE(TOUCH_EVENTS) // Android
3153 #define MOTION_EVENT_ACTION_POINTER_DOWN 5
3154 #define MOTION_EVENT_ACTION_POINTER_UP 6
3156 WebCore::TouchEventType type = WebCore::TouchStart;
3157 WebCore::PlatformTouchPoint::State defaultTouchState;
3158 Vector<WebCore::PlatformTouchPoint::State> touchStates(points.size());
3161 case 0: // MotionEvent.ACTION_DOWN
3162 type = WebCore::TouchStart;
3163 defaultTouchState = WebCore::PlatformTouchPoint::TouchPressed;
3165 case 1: // MotionEvent.ACTION_UP
3166 type = WebCore::TouchEnd;
3167 defaultTouchState = WebCore::PlatformTouchPoint::TouchReleased;
3169 case 2: // MotionEvent.ACTION_MOVE
3170 type = WebCore::TouchMove;
3171 defaultTouchState = WebCore::PlatformTouchPoint::TouchMoved;
3173 case 3: // MotionEvent.ACTION_CANCEL
3174 type = WebCore::TouchCancel;
3175 defaultTouchState = WebCore::PlatformTouchPoint::TouchCancelled;
3177 case 5: // MotionEvent.ACTION_POINTER_DOWN
3178 type = WebCore::TouchStart;
3179 defaultTouchState = WebCore::PlatformTouchPoint::TouchStationary;
3181 case 6: // MotionEvent.ACTION_POINTER_UP
3182 type = WebCore::TouchEnd;
3183 defaultTouchState = WebCore::PlatformTouchPoint::TouchStationary;
3185 case 0x100: // WebViewCore.ACTION_LONGPRESS
3186 type = WebCore::TouchLongPress;
3187 defaultTouchState = WebCore::PlatformTouchPoint::TouchPressed;
3189 case 0x200: // WebViewCore.ACTION_DOUBLETAP
3190 type = WebCore::TouchDoubleTap;
3191 defaultTouchState = WebCore::PlatformTouchPoint::TouchPressed;
3194 // We do not support other kinds of touch event inside WebCore
3196 LOGW("Java passed a touch event type that we do not support in WebCore: %d", action);
3200 for (int c = 0; c < static_cast<int>(points.size()); c++) {
3201 points[c].setX(points[c].x() - m_scrollOffsetX);
3202 points[c].setY(points[c].y() - m_scrollOffsetY);
3204 // Setting the touch state for each point.
3205 // Note: actionIndex will be 0 for all actions that are not ACTION_POINTER_DOWN/UP.
3206 if (action == MOTION_EVENT_ACTION_POINTER_DOWN && c == actionIndex) {
3207 touchStates[c] = WebCore::PlatformTouchPoint::TouchPressed;
3208 } else if (action == MOTION_EVENT_ACTION_POINTER_UP && c == actionIndex) {
3209 touchStates[c] = WebCore::PlatformTouchPoint::TouchReleased;
3211 touchStates[c] = defaultTouchState;
3215 WebCore::PlatformTouchEvent te(ids, points, type, touchStates, metaState);
3216 preventDefault = m_mainFrame->eventHandler()->handleTouchEvent(te);
3219 #if USE(ACCELERATED_COMPOSITING)
3221 rootLayer->pauseDisplay(false);
3223 return preventDefault;
3226 void WebViewCore::touchUp(int touchGeneration,
3227 WebCore::Frame* frame, WebCore::Node* node, int x, int y)
3229 if (touchGeneration == 0) {
3230 // m_mousePos should be set in getTouchHighlightRects()
3231 WebCore::HitTestResult hitTestResult = m_mainFrame->eventHandler()->hitTestResultAtPoint(m_mousePos, false);
3232 node = hitTestResult.innerNode();
3234 frame = node->document()->frame();
3237 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);
3239 if (m_touchGeneration > touchGeneration) {
3240 DBG_NAV_LOGD("m_touchGeneration=%d > touchGeneration=%d"
3241 " x=%d y=%d", m_touchGeneration, touchGeneration, x, y);
3242 return; // short circuit if a newer touch has been generated
3244 // This moves m_mousePos to the correct place, and handleMouseClick uses
3245 // m_mousePos to determine where the click happens.
3246 moveMouse(frame, x, y);
3247 m_lastGeneration = touchGeneration;
3249 if (frame && CacheBuilder::validNode(m_mainFrame, frame, 0)) {
3250 frame->loader()->resetMultipleFormSubmissionProtection();
3252 DBG_NAV_LOGD("touchGeneration=%d handleMouseClick frame=%p node=%p"
3253 " x=%d y=%d", touchGeneration, frame, node, x, y);
3254 handleMouseClick(frame, node, false);
3257 // Check for the "x-webkit-soft-keyboard" attribute. If it is there and
3258 // set to hidden, do not show the soft keyboard. Node passed as a parameter
3259 // must not be null.
3260 static bool shouldSuppressKeyboard(const WebCore::Node* node) {
3261 LOG_ASSERT(node, "node passed to shouldSuppressKeyboard cannot be null");
3262 const NamedNodeMap* attributes = node->attributes();
3263 if (!attributes) return false;
3264 size_t length = attributes->length();
3265 for (size_t i = 0; i < length; i++) {
3266 const Attribute* a = attributes->attributeItem(i);
3267 if (a->localName() == "x-webkit-soft-keyboard" && a->value() == "hidden")
3273 // Common code for both clicking with the trackball and touchUp
3274 // Also used when typing into a non-focused textfield to give the textfield focus,
3275 // in which case, 'fake' is set to true
3276 bool WebViewCore::handleMouseClick(WebCore::Frame* framePtr, WebCore::Node* nodePtr, bool fake)
3278 bool valid = !framePtr || CacheBuilder::validNode(m_mainFrame, framePtr, nodePtr);
3279 WebFrame* webFrame = WebFrame::getWebFrame(m_mainFrame);
3280 if (valid && nodePtr) {
3281 // Need to special case area tags because an image map could have an area element in the middle
3282 // so when attempting to get the default, the point chosen would be follow the wrong link.
3283 if (nodePtr->hasTagName(WebCore::HTMLNames::areaTag)) {
3284 webFrame->setUserInitiatedAction(true);
3285 nodePtr->dispatchSimulatedClick(0, true, true);
3286 webFrame->setUserInitiatedAction(false);
3287 DBG_NAV_LOG("area");
3291 if (!valid || !framePtr)
3292 framePtr = m_mainFrame;
3293 webFrame->setUserInitiatedAction(true);
3294 WebCore::PlatformMouseEvent mouseDown(m_mousePos, m_mousePos, WebCore::LeftButton,
3295 WebCore::MouseEventPressed, 1, false, false, false, false,
3296 WTF::currentTime());
3297 // ignore the return from as it will return true if the hit point can trigger selection change
3298 framePtr->eventHandler()->handleMousePressEvent(mouseDown);
3299 WebCore::PlatformMouseEvent mouseUp(m_mousePos, m_mousePos, WebCore::LeftButton,
3300 WebCore::MouseEventReleased, 1, false, false, false, false,
3301 WTF::currentTime());
3302 bool handled = framePtr->eventHandler()->handleMouseReleaseEvent(mouseUp);
3303 webFrame->setUserInitiatedAction(false);
3305 // If the user clicked on a textfield, make the focusController active
3306 // so we show the blinking cursor.
3307 WebCore::Node* focusNode = currentFocus();
3308 DBG_NAV_LOGD("m_mousePos={%d,%d} focusNode=%p handled=%s", m_mousePos.x(),
3309 m_mousePos.y(), focusNode, handled ? "true" : "false");
3311 WebCore::RenderObject* renderer = focusNode->renderer();
3312 if (renderer && (renderer->isTextField() || renderer->isTextArea())) {
3313 bool ime = !shouldSuppressKeyboard(focusNode)
3314 && !(static_cast<WebCore::HTMLInputElement*>(focusNode))->readOnly();
3316 #if ENABLE(WEB_AUTOFILL)
3317 if (renderer->isTextField()) {
3318 EditorClientAndroid* editorC = static_cast<EditorClientAndroid*>(framePtr->page()->editorClient());
3319 WebAutofill* autoFill = editorC->getAutofill();
3320 autoFill->formFieldFocused(static_cast<HTMLFormControlElement*>(focusNode));
3324 RenderTextControl* rtc
3325 = static_cast<RenderTextControl*> (renderer);
3326 // Force an update of the navcache as this will fire off a
3327 // message to WebView that *must* have an updated focus.
3328 m_frameCacheOutOfDate = true;
3330 requestKeyboardWithSelection(focusNode, rtc->selectionStart(),
3331 rtc->selectionEnd());
3334 requestKeyboard(false);
3337 // If the selection is contentEditable, show the keyboard so the
3338 // user can type. Otherwise hide the keyboard because no text
3340 if (isContentEditable(focusNode)) {
3341 requestKeyboard(true);
3342 } else if (!nodeIsPlugin(focusNode)) {
3347 // There is no focusNode, so the keyboard is not needed.
3353 void WebViewCore::popupReply(int index)
3356 m_popupReply->replyInt(index);
3357 Release(m_popupReply);
3362 void WebViewCore::popupReply(const int* array, int count)
3365 m_popupReply->replyIntArray(array, count);
3366 Release(m_popupReply);
3371 void WebViewCore::formDidBlur(const WebCore::Node* node)
3373 // If the blur is on a text input, keep track of the node so we can
3374 // hide the soft keyboard when the new focus is set, if it is not a
3376 if (isTextInput(node))
3377 m_blurringNodePointer = reinterpret_cast<int>(node);
3380 void WebViewCore::focusNodeChanged(const WebCore::Node* newFocus)
3382 if (isTextInput(newFocus))
3383 m_shouldPaintCaret = true;
3384 else if (m_blurringNodePointer) {
3385 JNIEnv* env = JSC::Bindings::getJNIEnv();
3386 AutoJObject javaObject = m_javaGlue->object(env);
3387 if (!javaObject.get())
3389 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_formDidBlur, m_blurringNodePointer);
3390 checkException(env);
3391 m_blurringNodePointer = 0;
3395 void WebViewCore::addMessageToConsole(const WTF::String& message, unsigned int lineNumber, const WTF::String& sourceID, int msgLevel) {
3396 JNIEnv* env = JSC::Bindings::getJNIEnv();
3397 AutoJObject javaObject = m_javaGlue->object(env);
3398 if (!javaObject.get())
3400 jstring jMessageStr = wtfStringToJstring(env, message);
3401 jstring jSourceIDStr = wtfStringToJstring(env, sourceID);
3402 env->CallVoidMethod(javaObject.get(),
3403 m_javaGlue->m_addMessageToConsole, jMessageStr, lineNumber,
3404 jSourceIDStr, msgLevel);
3405 env->DeleteLocalRef(jMessageStr);
3406 env->DeleteLocalRef(jSourceIDStr);
3407 checkException(env);
3410 void WebViewCore::jsAlert(const WTF::String& url, const WTF::String& text)
3412 JNIEnv* env = JSC::Bindings::getJNIEnv();
3413 AutoJObject javaObject = m_javaGlue->object(env);
3414 if (!javaObject.get())
3416 jstring jInputStr = wtfStringToJstring(env, text);
3417 jstring jUrlStr = wtfStringToJstring(env, url);
3418 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_jsAlert, jUrlStr, jInputStr);
3419 env->DeleteLocalRef(jInputStr);
3420 env->DeleteLocalRef(jUrlStr);
3421 checkException(env);
3424 bool WebViewCore::exceededDatabaseQuota(const WTF::String& url, const WTF::String& databaseIdentifier, const unsigned long long currentQuota, unsigned long long estimatedSize)
3426 #if ENABLE(DATABASE)
3427 JNIEnv* env = JSC::Bindings::getJNIEnv();
3428 AutoJObject javaObject = m_javaGlue->object(env);
3429 if (!javaObject.get())
3431 jstring jDatabaseIdentifierStr = wtfStringToJstring(env, databaseIdentifier);
3432 jstring jUrlStr = wtfStringToJstring(env, url);
3433 env->CallVoidMethod(javaObject.get(),
3434 m_javaGlue->m_exceededDatabaseQuota, jUrlStr,
3435 jDatabaseIdentifierStr, currentQuota, estimatedSize);
3436 env->DeleteLocalRef(jDatabaseIdentifierStr);
3437 env->DeleteLocalRef(jUrlStr);
3438 checkException(env);
3443 bool WebViewCore::reachedMaxAppCacheSize(const unsigned long long spaceNeeded)
3445 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
3446 JNIEnv* env = JSC::Bindings::getJNIEnv();
3447 AutoJObject javaObject = m_javaGlue->object(env);
3448 if (!javaObject.get())
3450 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_reachedMaxAppCacheSize, spaceNeeded);
3451 checkException(env);
3456 void WebViewCore::populateVisitedLinks(WebCore::PageGroup* group)
3458 JNIEnv* env = JSC::Bindings::getJNIEnv();
3459 AutoJObject javaObject = m_javaGlue->object(env);
3460 if (!javaObject.get())
3462 m_groupForVisitedLinks = group;
3463 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_populateVisitedLinks);
3464 checkException(env);
3467 void WebViewCore::geolocationPermissionsShowPrompt(const WTF::String& origin)
3469 JNIEnv* env = JSC::Bindings::getJNIEnv();
3470 AutoJObject javaObject = m_javaGlue->object(env);
3471 if (!javaObject.get())
3473 jstring originString = wtfStringToJstring(env, origin);
3474 env->CallVoidMethod(javaObject.get(),
3475 m_javaGlue->m_geolocationPermissionsShowPrompt,
3477 env->DeleteLocalRef(originString);
3478 checkException(env);
3481 void WebViewCore::geolocationPermissionsHidePrompt()
3483 JNIEnv* env = JSC::Bindings::getJNIEnv();
3484 AutoJObject javaObject = m_javaGlue->object(env);
3485 if (!javaObject.get())
3487 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_geolocationPermissionsHidePrompt);
3488 checkException(env);
3491 jobject WebViewCore::getDeviceMotionService()
3493 JNIEnv* env = JSC::Bindings::getJNIEnv();
3494 AutoJObject javaObject = m_javaGlue->object(env);
3495 if (!javaObject.get())
3497 jobject object = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_getDeviceMotionService);
3498 checkException(env);
3502 jobject WebViewCore::getDeviceOrientationService()
3504 JNIEnv* env = JSC::Bindings::getJNIEnv();
3505 AutoJObject javaObject = m_javaGlue->object(env);
3506 if (!javaObject.get())
3508 jobject object = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_getDeviceOrientationService);
3509 checkException(env);
3513 bool WebViewCore::jsConfirm(const WTF::String& url, const WTF::String& text)
3515 JNIEnv* env = JSC::Bindings::getJNIEnv();
3516 AutoJObject javaObject = m_javaGlue->object(env);
3517 if (!javaObject.get())
3519 jstring jInputStr = wtfStringToJstring(env, text);
3520 jstring jUrlStr = wtfStringToJstring(env, url);
3521 jboolean result = env->CallBooleanMethod(javaObject.get(), m_javaGlue->m_jsConfirm, jUrlStr, jInputStr);
3522 env->DeleteLocalRef(jInputStr);
3523 env->DeleteLocalRef(jUrlStr);
3524 checkException(env);
3528 bool WebViewCore::jsPrompt(const WTF::String& url, const WTF::String& text, const WTF::String& defaultValue, WTF::String& result)
3530 JNIEnv* env = JSC::Bindings::getJNIEnv();
3531 AutoJObject javaObject = m_javaGlue->object(env);
3532 if (!javaObject.get())
3534 jstring jUrlStr = wtfStringToJstring(env, url);
3535 jstring jInputStr = wtfStringToJstring(env, text);
3536 jstring jDefaultStr = wtfStringToJstring(env, defaultValue);
3537 jstring returnVal = static_cast<jstring>(env->CallObjectMethod(javaObject.get(), m_javaGlue->m_jsPrompt, jUrlStr, jInputStr, jDefaultStr));
3538 env->DeleteLocalRef(jUrlStr);
3539 env->DeleteLocalRef(jInputStr);
3540 env->DeleteLocalRef(jDefaultStr);
3541 checkException(env);
3543 // If returnVal is null, it means that the user cancelled the dialog.
3547 result = jstringToWtfString(env, returnVal);
3548 env->DeleteLocalRef(returnVal);
3552 bool WebViewCore::jsUnload(const WTF::String& url, const WTF::String& message)
3554 JNIEnv* env = JSC::Bindings::getJNIEnv();
3555 AutoJObject javaObject = m_javaGlue->object(env);
3556 if (!javaObject.get())
3558 jstring jInputStr = wtfStringToJstring(env, message);
3559 jstring jUrlStr = wtfStringToJstring(env, url);
3560 jboolean result = env->CallBooleanMethod(javaObject.get(), m_javaGlue->m_jsUnload, jUrlStr, jInputStr);
3561 env->DeleteLocalRef(jInputStr);
3562 env->DeleteLocalRef(jUrlStr);
3563 checkException(env);
3567 bool WebViewCore::jsInterrupt()
3569 JNIEnv* env = JSC::Bindings::getJNIEnv();
3570 AutoJObject javaObject = m_javaGlue->object(env);
3571 if (!javaObject.get())
3573 jboolean result = env->CallBooleanMethod(javaObject.get(), m_javaGlue->m_jsInterrupt);
3574 checkException(env);
3579 WebViewCore::getJavaObject()
3581 return m_javaGlue->object(JSC::Bindings::getJNIEnv());
3585 WebViewCore::getWebViewJavaObject()
3587 JNIEnv* env = JSC::Bindings::getJNIEnv();
3588 AutoJObject javaObject = m_javaGlue->object(env);
3589 if (!javaObject.get())
3591 return env->GetObjectField(javaObject.get(), gWebViewCoreFields.m_webView);
3594 void WebViewCore::updateTextSelection()
3596 JNIEnv* env = JSC::Bindings::getJNIEnv();
3597 AutoJObject javaObject = m_javaGlue->object(env);
3598 if (!javaObject.get())
3600 WebCore::Node* focusNode = currentFocus();
3603 RenderObject* renderer = focusNode->renderer();
3604 if (!renderer || (!renderer->isTextArea() && !renderer->isTextField()))
3606 RenderTextControl* rtc = static_cast<RenderTextControl*>(renderer);
3607 env->CallVoidMethod(javaObject.get(),
3608 m_javaGlue->m_updateTextSelection, reinterpret_cast<int>(focusNode),
3609 rtc->selectionStart(), rtc->selectionEnd(), m_textGeneration);
3610 checkException(env);
3613 void WebViewCore::updateTextfield(WebCore::Node* ptr, bool changeToPassword,
3614 const WTF::String& text)
3616 JNIEnv* env = JSC::Bindings::getJNIEnv();
3617 AutoJObject javaObject = m_javaGlue->object(env);
3618 if (!javaObject.get())
3620 if (m_blockTextfieldUpdates)
3622 if (changeToPassword) {
3623 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_updateTextfield,
3624 (int) ptr, true, 0, m_textGeneration);
3625 checkException(env);
3628 jstring string = wtfStringToJstring(env, text);
3629 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_updateTextfield,
3630 (int) ptr, false, string, m_textGeneration);
3631 env->DeleteLocalRef(string);
3632 checkException(env);
3635 void WebViewCore::clearTextEntry()
3637 JNIEnv* env = JSC::Bindings::getJNIEnv();
3638 AutoJObject javaObject = m_javaGlue->object(env);
3639 if (!javaObject.get())
3641 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_clearTextEntry);
3644 void WebViewCore::setBackgroundColor(SkColor c)
3646 WebCore::FrameView* view = m_mainFrame->view();
3650 // need (int) cast to find the right constructor
3651 WebCore::Color bcolor((int)SkColorGetR(c), (int)SkColorGetG(c),
3652 (int)SkColorGetB(c), (int)SkColorGetA(c));
3653 view->setBaseBackgroundColor(bcolor);
3655 // Background color of 0 indicates we want a transparent background
3657 view->setTransparent(true);
3660 jclass WebViewCore::getPluginClass(const WTF::String& libName, const char* className)
3662 JNIEnv* env = JSC::Bindings::getJNIEnv();
3663 AutoJObject javaObject = m_javaGlue->object(env);
3664 if (!javaObject.get())
3667 jstring libString = wtfStringToJstring(env, libName);
3668 jstring classString = env->NewStringUTF(className);
3669 jobject pluginClass = env->CallObjectMethod(javaObject.get(),
3670 m_javaGlue->m_getPluginClass,
3671 libString, classString);
3672 checkException(env);
3674 // cleanup unneeded local JNI references
3675 env->DeleteLocalRef(libString);
3676 env->DeleteLocalRef(classString);
3678 if (pluginClass != 0) {
3679 return static_cast<jclass>(pluginClass);
3685 void WebViewCore::showFullScreenPlugin(jobject childView, int32_t orientation, NPP npp)
3687 JNIEnv* env = JSC::Bindings::getJNIEnv();
3688 AutoJObject javaObject = m_javaGlue->object(env);
3689 if (!javaObject.get())
3692 env->CallVoidMethod(javaObject.get(),
3693 m_javaGlue->m_showFullScreenPlugin,
3694 childView, orientation, reinterpret_cast<int>(npp));
3695 checkException(env);
3698 void WebViewCore::hideFullScreenPlugin()
3700 JNIEnv* env = JSC::Bindings::getJNIEnv();
3701 AutoJObject javaObject = m_javaGlue->object(env);
3702 if (!javaObject.get())
3704 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_hideFullScreenPlugin);
3705 checkException(env);
3708 jobject WebViewCore::createSurface(jobject view)
3710 JNIEnv* env = JSC::Bindings::getJNIEnv();
3711 AutoJObject javaObject = m_javaGlue->object(env);
3712 if (!javaObject.get())
3714 jobject result = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_createSurface, view);
3715 checkException(env);
3719 jobject WebViewCore::addSurface(jobject view, int x, int y, int width, int height)
3721 JNIEnv* env = JSC::Bindings::getJNIEnv();
3722 AutoJObject javaObject = m_javaGlue->object(env);
3723 if (!javaObject.get())
3725 jobject result = env->CallObjectMethod(javaObject.get(),
3726 m_javaGlue->m_addSurface,
3727 view, x, y, width, height);
3728 checkException(env);
3732 void WebViewCore::updateSurface(jobject childView, int x, int y, int width, int height)
3734 JNIEnv* env = JSC::Bindings::getJNIEnv();
3735 AutoJObject javaObject = m_javaGlue->object(env);
3736 if (!javaObject.get())
3738 env->CallVoidMethod(javaObject.get(),
3739 m_javaGlue->m_updateSurface, childView,
3740 x, y, width, height);
3741 checkException(env);
3744 void WebViewCore::destroySurface(jobject childView)
3746 JNIEnv* env = JSC::Bindings::getJNIEnv();
3747 AutoJObject javaObject = m_javaGlue->object(env);
3748 if (!javaObject.get())
3750 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_destroySurface, childView);
3751 checkException(env);
3754 jobject WebViewCore::getContext()
3756 JNIEnv* env = JSC::Bindings::getJNIEnv();
3757 AutoJObject javaObject = m_javaGlue->object(env);
3758 if (!javaObject.get())
3761 jobject result = env->CallObjectMethod(javaObject.get(), m_javaGlue->m_getContext);
3762 checkException(env);
3766 void WebViewCore::keepScreenOn(bool screenOn) {
3767 if ((screenOn && m_screenOnCounter == 0) || (!screenOn && m_screenOnCounter == 1)) {
3768 JNIEnv* env = JSC::Bindings::getJNIEnv();
3769 AutoJObject javaObject = m_javaGlue->object(env);
3770 if (!javaObject.get())
3772 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_keepScreenOn, screenOn);
3773 checkException(env);
3776 // update the counter
3778 m_screenOnCounter++;
3779 else if (m_screenOnCounter > 0)
3780 m_screenOnCounter--;
3783 bool WebViewCore::validNodeAndBounds(Frame* frame, Node* node,
3784 const IntRect& originalAbsoluteBounds)
3786 bool valid = CacheBuilder::validNode(m_mainFrame, frame, node);
3789 RenderObject* renderer = node->renderer();
3792 IntRect absBounds = node->hasTagName(HTMLNames::areaTag)
3793 ? CacheBuilder::getAreaRect(static_cast<HTMLAreaElement*>(node))
3794 : renderer->absoluteBoundingBoxRect();
3795 return absBounds == originalAbsoluteBounds;
3798 void WebViewCore::showRect(int left, int top, int width, int height,
3799 int contentWidth, int contentHeight, float xPercentInDoc,
3800 float xPercentInView, float yPercentInDoc, float yPercentInView)
3802 JNIEnv* env = JSC::Bindings::getJNIEnv();
3803 AutoJObject javaObject = m_javaGlue->object(env);
3804 if (!javaObject.get())
3806 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_showRect,
3807 left, top, width, height, contentWidth, contentHeight,
3808 xPercentInDoc, xPercentInView, yPercentInDoc, yPercentInView);
3809 checkException(env);
3812 void WebViewCore::centerFitRect(int x, int y, int width, int height)
3814 JNIEnv* env = JSC::Bindings::getJNIEnv();
3815 AutoJObject javaObject = m_javaGlue->object(env);
3816 if (!javaObject.get())
3818 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_centerFitRect, x, y, width, height);
3819 checkException(env);
3822 void WebViewCore::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode verticalMode)
3824 JNIEnv* env = JSC::Bindings::getJNIEnv();
3825 AutoJObject javaObject = m_javaGlue->object(env);
3826 if (!javaObject.get())
3828 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_setScrollbarModes, horizontalMode, verticalMode);
3829 checkException(env);
3832 void WebViewCore::notifyWebAppCanBeInstalled()
3834 JNIEnv* env = JSC::Bindings::getJNIEnv();
3835 AutoJObject javaObject = m_javaGlue->object(env);
3836 if (!javaObject.get())
3838 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_setInstallableWebApp);
3839 checkException(env);
3843 void WebViewCore::enterFullscreenForVideoLayer(int layerId, const WTF::String& url)
3845 JNIEnv* env = JSC::Bindings::getJNIEnv();
3846 AutoJObject javaObject = m_javaGlue->object(env);
3847 if (!javaObject.get())
3849 jstring jUrlStr = wtfStringToJstring(env, url);
3850 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_enterFullscreenForVideoLayer, layerId, jUrlStr);
3851 checkException(env);
3855 void WebViewCore::setWebTextViewAutoFillable(int queryId, const string16& previewSummary)
3857 #if ENABLE(WEB_AUTOFILL)
3858 JNIEnv* env = JSC::Bindings::getJNIEnv();
3859 AutoJObject javaObject = m_javaGlue->object(env);
3860 if (!javaObject.get())
3862 jstring preview = env->NewString(previewSummary.data(), previewSummary.length());
3863 env->CallVoidMethod(javaObject.get(), m_javaGlue->m_setWebTextViewAutoFillable, queryId, preview);
3864 env->DeleteLocalRef(preview);
3868 bool WebViewCore::drawIsPaused() const
3870 // returning true says scrollview should be offscreen, which pauses
3871 // gifs. because this is not again queried when we stop scrolling, we don't
3872 // use the stopping currently.
3876 #if USE(CHROME_NETWORK_STACK)
3877 void WebViewCore::setWebRequestContextUserAgent()
3879 // We cannot create a WebRequestContext, because we might not know it this is a private tab or not yet
3880 if (m_webRequestContext)
3881 m_webRequestContext->setUserAgent(WebFrame::getWebFrame(m_mainFrame)->userAgentForURL(0)); // URL not used
3884 void WebViewCore::setWebRequestContextCacheMode(int cacheMode)
3886 m_cacheMode = cacheMode;
3887 // We cannot create a WebRequestContext, because we might not know it this is a private tab or not yet
3888 if (!m_webRequestContext)
3891 m_webRequestContext->setCacheMode(cacheMode);
3894 WebRequestContext* WebViewCore::webRequestContext()
3896 if (!m_webRequestContext) {
3897 Settings* settings = mainFrame()->settings();
3898 m_webRequestContext = new WebRequestContext(settings && settings->privateBrowsingEnabled());
3899 setWebRequestContextUserAgent();
3900 setWebRequestContextCacheMode(m_cacheMode);
3902 return m_webRequestContext.get();
3906 void WebViewCore::scrollRenderLayer(int layer, const SkRect& rect)
3908 #if USE(ACCELERATED_COMPOSITING)
3909 GraphicsLayerAndroid* root = graphicsRootLayer();
3913 LayerAndroid* layerAndroid = root->platformLayer();
3917 LayerAndroid* target = layerAndroid->findById(layer);
3921 RenderLayer* owner = target->owningLayer();
3925 if (owner->stackingContext())
3926 owner->scrollToOffset(rect.fLeft, rect.fTop);
3930 //----------------------------------------------------------------------
3931 // Native JNI methods
3932 //----------------------------------------------------------------------
3933 static void RevealSelection(JNIEnv *env, jobject obj)
3935 GET_NATIVE_VIEW(env, obj)->revealSelection();
3938 static jstring RequestLabel(JNIEnv *env, jobject obj, int framePointer,
3941 return wtfStringToJstring(env, GET_NATIVE_VIEW(env, obj)->requestLabel(
3942 (WebCore::Frame*) framePointer, (WebCore::Node*) nodePointer));
3945 static void ClearContent(JNIEnv *env, jobject obj)
3947 #ifdef ANDROID_INSTRUMENT
3948 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3950 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3951 viewImpl->clearContent();
3954 static void UpdateFrameCacheIfLoading(JNIEnv *env, jobject obj)
3956 GET_NATIVE_VIEW(env, obj)->updateFrameCacheIfLoading();
3959 static void SetSize(JNIEnv *env, jobject obj, jint width, jint height,
3960 jint textWrapWidth, jfloat scale, jint screenWidth, jint screenHeight,
3961 jint anchorX, jint anchorY, jboolean ignoreHeight)
3963 #ifdef ANDROID_INSTRUMENT
3964 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3966 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3967 LOGV("webviewcore::nativeSetSize(%u %u)\n viewImpl: %p", (unsigned)width, (unsigned)height, viewImpl);
3968 LOG_ASSERT(viewImpl, "viewImpl not set in nativeSetSize");
3969 viewImpl->setSizeScreenWidthAndScale(width, height, textWrapWidth, scale,
3970 screenWidth, screenHeight, anchorX, anchorY, ignoreHeight);
3973 static void SetScrollOffset(JNIEnv *env, jobject obj, jint gen, jboolean sendScrollEvent, jint x, jint y)
3975 #ifdef ANDROID_INSTRUMENT
3976 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3978 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3979 LOG_ASSERT(viewImpl, "need viewImpl");
3981 viewImpl->setScrollOffset(gen, sendScrollEvent, x, y);
3984 static void SetGlobalBounds(JNIEnv *env, jobject obj, jint x, jint y, jint h,
3987 #ifdef ANDROID_INSTRUMENT
3988 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
3990 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
3991 LOG_ASSERT(viewImpl, "need viewImpl");
3993 viewImpl->setGlobalBounds(x, y, h, v);
3996 static jboolean Key(JNIEnv *env, jobject obj, jint keyCode, jint unichar,
3997 jint repeatCount, jboolean isShift, jboolean isAlt, jboolean isSym,
4000 #ifdef ANDROID_INSTRUMENT
4001 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
4003 return GET_NATIVE_VIEW(env, obj)->key(PlatformKeyboardEvent(keyCode,
4004 unichar, repeatCount, isDown, isShift, isAlt, isSym));
4007 static void Click(JNIEnv *env, jobject obj, int framePtr, int nodePtr, jboolean fake)
4009 #ifdef ANDROID_INSTRUMENT
4010 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
4012 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
4013 LOG_ASSERT(viewImpl, "viewImpl not set in Click");
4015 viewImpl->click(reinterpret_cast<WebCore::Frame*>(framePtr),
4016 reinterpret_cast<WebCore::Node*>(nodePtr), fake);
4019 static void ContentInvalidateAll(JNIEnv *env, jobject obj)
4021 GET_NATIVE_VIEW(env, obj)->contentInvalidateAll();
4024 static void DeleteSelection(JNIEnv *env, jobject obj, jint start, jint end,
4025 jint textGeneration)
4027 #ifdef ANDROID_INSTRUMENT
4028 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
4030 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
4031 viewImpl->deleteSelection(start, end, textGeneration);
4034 static void SetSelection(JNIEnv *env, jobject obj, jint start, jint end)
4036 #ifdef ANDROID_INSTRUMENT
4037 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
4039 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
4040 viewImpl->setSelection(start, end);
4043 static jstring ModifySelection(JNIEnv *env, jobject obj, jint direction, jint granularity)
4045 #ifdef ANDROID_INSTRUMENT
4046 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
4048 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
4049 String selectionString = viewImpl->modifySelection(direction, granularity);
4050 return wtfStringToJstring(env, selectionString);
4053 static void ReplaceTextfieldText(JNIEnv *env, jobject obj,
4054 jint oldStart, jint oldEnd, jstring replace, jint start, jint end,
4055 jint textGeneration)
4057 #ifdef ANDROID_INSTRUMENT
4058 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
4060 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
4061 WTF::String webcoreString = jstringToWtfString(env, replace);
4062 viewImpl->replaceTextfieldText(oldStart,
4063 oldEnd, webcoreString, start, end, textGeneration);
4066 static void PassToJs(JNIEnv *env, jobject obj,
4067 jint generation, jstring currentText, jint keyCode,
4068 jint keyValue, jboolean down, jboolean cap, jboolean fn, jboolean sym)
4070 #ifdef ANDROID_INSTRUMENT
4071 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
4073 WTF::String current = jstringToWtfString(env, currentText);
4074 GET_NATIVE_VIEW(env, obj)->passToJs(generation, current,
4075 PlatformKeyboardEvent(keyCode, keyValue, 0, down, cap, fn, sym));
4078 static void ScrollFocusedTextInput(JNIEnv *env, jobject obj, jfloat xPercent,
4081 #ifdef ANDROID_INSTRUMENT
4082 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
4084 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
4085 viewImpl->scrollFocusedTextInput(xPercent, y);
4088 static void SetFocusControllerActive(JNIEnv *env, jobject obj, jboolean active)
4090 #ifdef ANDROID_INSTRUMENT
4091 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
4093 LOGV("webviewcore::nativeSetFocusControllerActive()\n");
4094 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
4095 LOG_ASSERT(viewImpl, "viewImpl not set in nativeSetFocusControllerActive");
4096 viewImpl->setFocusControllerActive(active);
4099 static void SaveDocumentState(JNIEnv *env, jobject obj, jint frame)
4101 #ifdef ANDROID_INSTRUMENT
4102 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
4104 LOGV("webviewcore::nativeSaveDocumentState()\n");
4105 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
4106 LOG_ASSERT(viewImpl, "viewImpl not set in nativeSaveDocumentState");
4107 viewImpl->saveDocumentState((WebCore::Frame*) frame);
4110 void WebViewCore::addVisitedLink(const UChar* string, int length)
4112 if (m_groupForVisitedLinks)
4113 m_groupForVisitedLinks->addVisitedLink(string, length);
4116 static bool UpdateLayers(JNIEnv *env, jobject obj, jint nativeClass, jint jbaseLayer)
4118 WebViewCore* viewImpl = (WebViewCore*) nativeClass;
4119 BaseLayerAndroid* baseLayer = (BaseLayerAndroid*) jbaseLayer;
4121 LayerAndroid* root = static_cast<LayerAndroid*>(baseLayer->getChild(0));
4123 return viewImpl->updateLayers(root);
4128 static void NotifyAnimationStarted(JNIEnv *env, jobject obj, jint nativeClass)
4130 WebViewCore* viewImpl = (WebViewCore*) nativeClass;
4131 viewImpl->notifyAnimationStarted();
4134 static jint RecordContent(JNIEnv *env, jobject obj, jobject region, jobject pt)
4136 #ifdef ANDROID_INSTRUMENT
4137 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
4139 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
4140 SkRegion* nativeRegion = GraphicsJNI::getNativeRegion(env, region);
4142 BaseLayerAndroid* result = viewImpl->recordContent(nativeRegion, &nativePt);
4143 GraphicsJNI::ipoint_to_jpoint(nativePt, env, pt);
4144 return reinterpret_cast<jint>(result);
4147 static void SplitContent(JNIEnv *env, jobject obj, jint content)
4149 #ifdef ANDROID_INSTRUMENT
4150 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
4152 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
4153 viewImpl->splitContent(reinterpret_cast<PictureSet*>(content));
4156 static void SendListBoxChoice(JNIEnv* env, jobject obj, jint choice)
4158 #ifdef ANDROID_INSTRUMENT
4159 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
4161 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
4162 LOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoice");
4163 viewImpl->popupReply(choice);
4166 // Set aside a predetermined amount of space in which to place the listbox
4167 // choices, to avoid unnecessary allocations.
4168 // The size here is arbitrary. We want the size to be at least as great as the
4169 // number of items in the average multiple-select listbox.
4170 #define PREPARED_LISTBOX_STORAGE 10
4172 static void SendListBoxChoices(JNIEnv* env, jobject obj, jbooleanArray jArray,
4175 #ifdef ANDROID_INSTRUMENT
4176 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
4178 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
4179 LOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoices");
4180 jboolean* ptrArray = env->GetBooleanArrayElements(jArray, 0);
4181 SkAutoSTMalloc<PREPARED_LISTBOX_STORAGE, int> storage(size);
4182 int* array = storage.get();
4184 for (int i = 0; i < size; i++) {
4189 env->ReleaseBooleanArrayElements(jArray, ptrArray, JNI_ABORT);
4190 viewImpl->popupReply(array, count);
4193 static jstring FindAddress(JNIEnv *env, jobject obj, jstring addr,
4194 jboolean caseInsensitive)
4196 #ifdef ANDROID_INSTRUMENT
4197 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
4201 int length = env->GetStringLength(addr);
4204 const jchar* addrChars = env->GetStringChars(addr, 0);
4206 bool success = CacheBuilder::FindAddress(addrChars, length,
4207 &start, &end, caseInsensitive) == CacheBuilder::FOUND_COMPLETE;
4210 ret = env->NewString(addrChars + start, end - start);
4211 env->ReleaseStringChars(addr, addrChars);
4215 static jboolean HandleTouchEvent(JNIEnv *env, jobject obj, jint action, jintArray idArray,
4216 jintArray xArray, jintArray yArray,
4217 jint count, jint actionIndex, jint metaState)
4219 #ifdef ANDROID_INSTRUMENT
4220 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
4222 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
4223 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4224 jint* ptrIdArray = env->GetIntArrayElements(idArray, 0);
4225 jint* ptrXArray = env->GetIntArrayElements(xArray, 0);
4226 jint* ptrYArray = env->GetIntArrayElements(yArray, 0);
4227 Vector<int> ids(count);
4228 Vector<IntPoint> points(count);
4229 for (int c = 0; c < count; c++) {
4230 ids[c] = ptrIdArray[c];
4231 points[c].setX(ptrXArray[c]);
4232 points[c].setY(ptrYArray[c]);
4234 env->ReleaseIntArrayElements(idArray, ptrIdArray, JNI_ABORT);
4235 env->ReleaseIntArrayElements(xArray, ptrXArray, JNI_ABORT);
4236 env->ReleaseIntArrayElements(yArray, ptrYArray, JNI_ABORT);
4238 return viewImpl->handleTouchEvent(action, ids, points, actionIndex, metaState);
4241 static void TouchUp(JNIEnv *env, jobject obj, jint touchGeneration,
4242 jint frame, jint node, jint x, jint y)
4244 #ifdef ANDROID_INSTRUMENT
4245 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
4247 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
4248 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4249 viewImpl->touchUp(touchGeneration,
4250 (WebCore::Frame*) frame, (WebCore::Node*) node, x, y);
4253 static jstring RetrieveHref(JNIEnv *env, jobject obj, jint x, jint y)
4255 #ifdef ANDROID_INSTRUMENT
4256 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
4258 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
4259 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4260 WTF::String result = viewImpl->retrieveHref(x, y);
4261 if (!result.isEmpty())
4262 return wtfStringToJstring(env, result);
4266 static jstring RetrieveAnchorText(JNIEnv *env, jobject obj, jint x, jint y)
4268 #ifdef ANDROID_INSTRUMENT
4269 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
4271 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
4272 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4273 WTF::String result = viewImpl->retrieveAnchorText(x, y);
4274 if (!result.isEmpty())
4275 return wtfStringToJstring(env, result);
4279 static jstring RetrieveImageSource(JNIEnv *env, jobject obj, jint x, jint y)
4281 WTF::String result = GET_NATIVE_VIEW(env, obj)->retrieveImageSource(x, y);
4282 return !result.isEmpty() ? wtfStringToJstring(env, result) : 0;
4285 static void StopPaintingCaret(JNIEnv *env, jobject obj)
4287 GET_NATIVE_VIEW(env, obj)->setShouldPaintCaret(false);
4290 static void MoveFocus(JNIEnv *env, jobject obj, jint framePtr, jint nodePtr)
4292 #ifdef ANDROID_INSTRUMENT
4293 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
4295 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
4296 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4297 viewImpl->moveFocus((WebCore::Frame*) framePtr, (WebCore::Node*) nodePtr);
4300 static void MoveMouse(JNIEnv *env, jobject obj, jint frame,
4303 #ifdef ANDROID_INSTRUMENT
4304 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
4306 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
4307 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4308 viewImpl->moveMouse((WebCore::Frame*) frame, x, y);
4311 static void MoveMouseIfLatest(JNIEnv *env, jobject obj, jint moveGeneration,
4312 jint frame, jint x, jint y)
4314 #ifdef ANDROID_INSTRUMENT
4315 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
4317 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
4318 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4319 viewImpl->moveMouseIfLatest(moveGeneration,
4320 (WebCore::Frame*) frame, x, y);
4323 static void UpdateFrameCache(JNIEnv *env, jobject obj)
4325 #ifdef ANDROID_INSTRUMENT
4326 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
4328 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
4329 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4330 viewImpl->updateFrameCache();
4333 static jint GetContentMinPrefWidth(JNIEnv *env, jobject obj)
4335 #ifdef ANDROID_INSTRUMENT
4336 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
4338 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
4339 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4341 WebCore::Frame* frame = viewImpl->mainFrame();
4343 WebCore::Document* document = frame->document();
4345 WebCore::RenderObject* renderer = document->renderer();
4346 if (renderer && renderer->isRenderView()) {
4347 return renderer->minPreferredLogicalWidth();
4354 static void SetViewportSettingsFromNative(JNIEnv *env, jobject obj)
4356 #ifdef ANDROID_INSTRUMENT
4357 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
4359 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
4360 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4362 WebCore::Settings* s = viewImpl->mainFrame()->page()->settings();
4366 #ifdef ANDROID_META_SUPPORT
4367 env->SetIntField(obj, gWebViewCoreFields.m_viewportWidth, s->viewportWidth());
4368 env->SetIntField(obj, gWebViewCoreFields.m_viewportHeight, s->viewportHeight());
4369 env->SetIntField(obj, gWebViewCoreFields.m_viewportInitialScale, s->viewportInitialScale());
4370 env->SetIntField(obj, gWebViewCoreFields.m_viewportMinimumScale, s->viewportMinimumScale());
4371 env->SetIntField(obj, gWebViewCoreFields.m_viewportMaximumScale, s->viewportMaximumScale());
4372 env->SetBooleanField(obj, gWebViewCoreFields.m_viewportUserScalable, s->viewportUserScalable());
4373 env->SetIntField(obj, gWebViewCoreFields.m_viewportDensityDpi, s->viewportTargetDensityDpi());
4377 static void SetBackgroundColor(JNIEnv *env, jobject obj, jint color)
4379 #ifdef ANDROID_INSTRUMENT
4380 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
4382 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
4383 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4385 viewImpl->setBackgroundColor((SkColor) color);
4388 static void DumpDomTree(JNIEnv *env, jobject obj, jboolean useFile)
4390 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
4391 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4393 viewImpl->dumpDomTree(useFile);
4396 static void DumpRenderTree(JNIEnv *env, jobject obj, jboolean useFile)
4398 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
4399 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4401 viewImpl->dumpRenderTree(useFile);
4404 static void DumpNavTree(JNIEnv *env, jobject obj)
4406 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
4407 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4409 viewImpl->dumpNavTree();
4412 static void DumpV8Counters(JNIEnv*, jobject)
4415 #ifdef ANDROID_INSTRUMENT
4416 V8Counters::dumpCounters();
4421 static void SetJsFlags(JNIEnv *env, jobject obj, jstring flags)
4424 WTF::String flagsString = jstringToWtfString(env, flags);
4425 WTF::CString utf8String = flagsString.utf8();
4426 WebCore::ScriptController::setFlags(utf8String.data(), utf8String.length());
4431 // Called from the Java side to set a new quota for the origin or new appcache
4432 // max size in response to a notification that the original quota was exceeded or
4433 // that the appcache has reached its maximum size.
4434 static void SetNewStorageLimit(JNIEnv* env, jobject obj, jlong quota) {
4435 #if ENABLE(DATABASE) || ENABLE(OFFLINE_WEB_APPLICATIONS)
4436 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
4437 Frame* frame = viewImpl->mainFrame();
4439 // The main thread is blocked awaiting this response, so now we can wake it
4441 ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client());
4442 chromeC->wakeUpMainThreadWithNewQuota(quota);
4446 // Called from Java to provide a Geolocation permission state for the specified origin.
4447 static void GeolocationPermissionsProvide(JNIEnv* env, jobject obj, jstring origin, jboolean allow, jboolean remember) {
4448 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
4449 Frame* frame = viewImpl->mainFrame();
4451 ChromeClientAndroid* chromeClient = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client());
4452 chromeClient->provideGeolocationPermissions(jstringToWtfString(env, origin), allow, remember);
4455 static void RegisterURLSchemeAsLocal(JNIEnv* env, jobject obj, jstring scheme) {
4456 #ifdef ANDROID_INSTRUMENT
4457 TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter);
4459 WebCore::SchemeRegistry::registerURLSchemeAsLocal(jstringToWtfString(env, scheme));
4462 static bool FocusBoundsChanged(JNIEnv* env, jobject obj)
4464 return GET_NATIVE_VIEW(env, obj)->focusBoundsChanged();
4467 static void SetIsPaused(JNIEnv* env, jobject obj, jboolean isPaused)
4469 // tell the webcore thread to stop thinking while we do other work
4470 // (selection and scrolling). This has nothing to do with the lifecycle
4471 // pause and resume.
4472 GET_NATIVE_VIEW(env, obj)->setIsPaused(isPaused);
4475 static void Pause(JNIEnv* env, jobject obj)
4477 // This is called for the foreground tab when the browser is put to the
4478 // background (and also for any tab when it is put to the background of the
4479 // browser). The browser can only be killed by the system when it is in the
4480 // background, so saving the Geolocation permission state now ensures that
4481 // is maintained when the browser is killed.
4482 ChromeClient* chromeClient = GET_NATIVE_VIEW(env, obj)->mainFrame()->page()->chrome()->client();
4483 ChromeClientAndroid* chromeClientAndroid = static_cast<ChromeClientAndroid*>(chromeClient);
4484 chromeClientAndroid->storeGeolocationPermissions();
4486 Frame* mainFrame = GET_NATIVE_VIEW(env, obj)->mainFrame();
4487 for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) {
4488 Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation();
4490 geolocation->suspend();
4493 GET_NATIVE_VIEW(env, obj)->deviceMotionAndOrientationManager()->maybeSuspendClients();
4496 SkANP::InitEvent(&event, kLifecycle_ANPEventType);
4497 event.data.lifecycle.action = kPause_ANPLifecycleAction;
4498 GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event);
4500 GET_NATIVE_VIEW(env, obj)->setIsPaused(true);
4503 static void Resume(JNIEnv* env, jobject obj)
4505 Frame* mainFrame = GET_NATIVE_VIEW(env, obj)->mainFrame();
4506 for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) {
4507 Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation();
4509 geolocation->resume();
4512 GET_NATIVE_VIEW(env, obj)->deviceMotionAndOrientationManager()->maybeResumeClients();
4515 SkANP::InitEvent(&event, kLifecycle_ANPEventType);
4516 event.data.lifecycle.action = kResume_ANPLifecycleAction;
4517 GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event);
4519 GET_NATIVE_VIEW(env, obj)->setIsPaused(false);
4522 static void FreeMemory(JNIEnv* env, jobject obj)
4525 SkANP::InitEvent(&event, kLifecycle_ANPEventType);
4526 event.data.lifecycle.action = kFreeMemory_ANPLifecycleAction;
4527 GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event);
4530 static void ProvideVisitedHistory(JNIEnv *env, jobject obj, jobject hist)
4532 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
4533 LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
4535 jobjectArray array = static_cast<jobjectArray>(hist);
4537 jsize len = env->GetArrayLength(array);
4538 for (jsize i = 0; i < len; i++) {
4539 jstring item = static_cast<jstring>(env->GetObjectArrayElement(array, i));
4540 const UChar* str = static_cast<const UChar*>(env->GetStringChars(item, 0));
4541 jsize len = env->GetStringLength(item);
4542 viewImpl->addVisitedLink(str, len);
4543 env->ReleaseStringChars(item, str);
4544 env->DeleteLocalRef(item);
4548 static void PluginSurfaceReady(JNIEnv* env, jobject obj)
4550 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
4552 viewImpl->sendPluginSurfaceReady();
4555 // Notification from the UI thread that the plugin's full-screen surface has been discarded
4556 static void FullScreenPluginHidden(JNIEnv* env, jobject obj, jint npp)
4558 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
4559 PluginWidgetAndroid* plugin = viewImpl->getPluginWidget((NPP)npp);
4561 plugin->exitFullScreen(false);
4564 static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj)
4567 GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B);
4568 return WebCore::IntRect(L, T, R - L, B - T);
4571 static bool ValidNodeAndBounds(JNIEnv *env, jobject obj, int frame, int node,
4574 IntRect nativeRect = jrect_to_webrect(env, rect);
4575 return GET_NATIVE_VIEW(env, obj)->validNodeAndBounds(
4576 reinterpret_cast<Frame*>(frame),
4577 reinterpret_cast<Node*>(node), nativeRect);
4580 static jobject GetTouchHighlightRects(JNIEnv* env, jobject obj, jint x, jint y, jint slop)
4582 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
4585 Vector<IntRect> rects = viewImpl->getTouchHighlightRects(x, y, slop);
4586 if (rects.isEmpty())
4589 jclass arrayClass = env->FindClass("java/util/ArrayList");
4590 LOG_ASSERT(arrayClass, "Could not find java/util/ArrayList");
4591 jmethodID init = env->GetMethodID(arrayClass, "<init>", "(I)V");
4592 LOG_ASSERT(init, "Could not find constructor for ArrayList");
4593 jobject array = env->NewObject(arrayClass, init, rects.size());
4594 LOG_ASSERT(array, "Could not create a new ArrayList");
4595 jmethodID add = env->GetMethodID(arrayClass, "add", "(Ljava/lang/Object;)Z");
4596 LOG_ASSERT(add, "Could not find add method on ArrayList");
4597 jclass rectClass = env->FindClass("android/graphics/Rect");
4598 LOG_ASSERT(rectClass, "Could not find android/graphics/Rect");
4599 jmethodID rectinit = env->GetMethodID(rectClass, "<init>", "(IIII)V");
4600 LOG_ASSERT(rectinit, "Could not find init method on Rect");
4602 for (size_t i = 0; i < rects.size(); i++) {
4603 jobject rect = env->NewObject(rectClass, rectinit, rects[i].x(),
4604 rects[i].y(), rects[i].maxX(), rects[i].maxY());
4606 env->CallBooleanMethod(array, add, rect);
4607 env->DeleteLocalRef(rect);
4611 env->DeleteLocalRef(rectClass);
4612 env->DeleteLocalRef(arrayClass);
4616 static void AutoFillForm(JNIEnv* env, jobject obj, jint queryId)
4618 #if ENABLE(WEB_AUTOFILL)
4619 WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
4623 WebCore::Frame* frame = viewImpl->mainFrame();
4625 EditorClientAndroid* editorC = static_cast<EditorClientAndroid*>(frame->page()->editorClient());
4626 WebAutofill* autoFill = editorC->getAutofill();
4627 autoFill->fillFormFields(queryId);
4632 static void CloseIdleConnections(JNIEnv* env, jobject obj)
4634 #if USE(CHROME_NETWORK_STACK)
4635 WebCache::get(true)->closeIdleConnections();
4636 WebCache::get(false)->closeIdleConnections();
4640 static void ScrollRenderLayer(JNIEnv* env, jobject obj, jint layer, jobject jRect)
4643 GraphicsJNI::jrect_to_rect(env, jRect, &rect);
4644 GET_NATIVE_VIEW(env, obj)->scrollRenderLayer(layer, rect);
4647 // ----------------------------------------------------------------------------
4652 static JNINativeMethod gJavaWebViewCoreMethods[] = {
4653 { "nativeClearContent", "()V",
4654 (void*) ClearContent },
4655 { "nativeFocusBoundsChanged", "()Z",
4656 (void*) FocusBoundsChanged } ,
4657 { "nativeKey", "(IIIZZZZ)Z",
4659 { "nativeClick", "(IIZ)V",
4661 { "nativeContentInvalidateAll", "()V",
4662 (void*) ContentInvalidateAll },
4663 { "nativeSendListBoxChoices", "([ZI)V",
4664 (void*) SendListBoxChoices },
4665 { "nativeSendListBoxChoice", "(I)V",
4666 (void*) SendListBoxChoice },
4667 { "nativeSetSize", "(IIIFIIIIZ)V",
4669 { "nativeSetScrollOffset", "(IZII)V",
4670 (void*) SetScrollOffset },
4671 { "nativeSetGlobalBounds", "(IIII)V",
4672 (void*) SetGlobalBounds },
4673 { "nativeSetSelection", "(II)V",
4674 (void*) SetSelection } ,
4675 { "nativeModifySelection", "(II)Ljava/lang/String;",
4676 (void*) ModifySelection },
4677 { "nativeDeleteSelection", "(III)V",
4678 (void*) DeleteSelection } ,
4679 { "nativeReplaceTextfieldText", "(IILjava/lang/String;III)V",
4680 (void*) ReplaceTextfieldText } ,
4681 { "nativeMoveFocus", "(II)V",
4682 (void*) MoveFocus },
4683 { "nativeMoveMouse", "(III)V",
4684 (void*) MoveMouse },
4685 { "nativeMoveMouseIfLatest", "(IIII)V",
4686 (void*) MoveMouseIfLatest },
4687 { "passToJs", "(ILjava/lang/String;IIZZZZ)V",
4689 { "nativeScrollFocusedTextInput", "(FI)V",
4690 (void*) ScrollFocusedTextInput },
4691 { "nativeSetFocusControllerActive", "(Z)V",
4692 (void*) SetFocusControllerActive },
4693 { "nativeSaveDocumentState", "(I)V",
4694 (void*) SaveDocumentState },
4695 { "nativeFindAddress", "(Ljava/lang/String;Z)Ljava/lang/String;",
4696 (void*) FindAddress },
4697 { "nativeHandleTouchEvent", "(I[I[I[IIII)Z",
4698 (void*) HandleTouchEvent },
4699 { "nativeTouchUp", "(IIIII)V",
4701 { "nativeRetrieveHref", "(II)Ljava/lang/String;",
4702 (void*) RetrieveHref },
4703 { "nativeRetrieveAnchorText", "(II)Ljava/lang/String;",
4704 (void*) RetrieveAnchorText },
4705 { "nativeRetrieveImageSource", "(II)Ljava/lang/String;",
4706 (void*) RetrieveImageSource },
4707 { "nativeStopPaintingCaret", "()V",
4708 (void*) StopPaintingCaret },
4709 { "nativeUpdateFrameCache", "()V",
4710 (void*) UpdateFrameCache },
4711 { "nativeGetContentMinPrefWidth", "()I",
4712 (void*) GetContentMinPrefWidth },
4713 { "nativeUpdateLayers", "(II)Z",
4714 (void*) UpdateLayers },
4715 { "nativeNotifyAnimationStarted", "(I)V",
4716 (void*) NotifyAnimationStarted },
4717 { "nativeRecordContent", "(Landroid/graphics/Region;Landroid/graphics/Point;)I",
4718 (void*) RecordContent },
4719 { "setViewportSettingsFromNative", "()V",
4720 (void*) SetViewportSettingsFromNative },
4721 { "nativeSplitContent", "(I)V",
4722 (void*) SplitContent },
4723 { "nativeSetBackgroundColor", "(I)V",
4724 (void*) SetBackgroundColor },
4725 { "nativeRegisterURLSchemeAsLocal", "(Ljava/lang/String;)V",
4726 (void*) RegisterURLSchemeAsLocal },
4727 { "nativeDumpDomTree", "(Z)V",
4728 (void*) DumpDomTree },
4729 { "nativeDumpRenderTree", "(Z)V",
4730 (void*) DumpRenderTree },
4731 { "nativeDumpNavTree", "()V",
4732 (void*) DumpNavTree },
4733 { "nativeDumpV8Counters", "()V",
4734 (void*) DumpV8Counters },
4735 { "nativeSetNewStorageLimit", "(J)V",
4736 (void*) SetNewStorageLimit },
4737 { "nativeGeolocationPermissionsProvide", "(Ljava/lang/String;ZZ)V",
4738 (void*) GeolocationPermissionsProvide },
4739 { "nativeSetIsPaused", "(Z)V", (void*) SetIsPaused },
4740 { "nativePause", "()V", (void*) Pause },
4741 { "nativeResume", "()V", (void*) Resume },
4742 { "nativeFreeMemory", "()V", (void*) FreeMemory },
4743 { "nativeSetJsFlags", "(Ljava/lang/String;)V", (void*) SetJsFlags },
4744 { "nativeRequestLabel", "(II)Ljava/lang/String;",
4745 (void*) RequestLabel },
4746 { "nativeRevealSelection", "()V", (void*) RevealSelection },
4747 { "nativeUpdateFrameCacheIfLoading", "()V",
4748 (void*) UpdateFrameCacheIfLoading },
4749 { "nativeProvideVisitedHistory", "([Ljava/lang/String;)V",
4750 (void*) ProvideVisitedHistory },
4751 { "nativeFullScreenPluginHidden", "(I)V",
4752 (void*) FullScreenPluginHidden },
4753 { "nativePluginSurfaceReady", "()V",
4754 (void*) PluginSurfaceReady },
4755 { "nativeValidNodeAndBounds", "(IILandroid/graphics/Rect;)Z",
4756 (void*) ValidNodeAndBounds },
4757 { "nativeGetTouchHighlightRects", "(III)Ljava/util/ArrayList;",
4758 (void*) GetTouchHighlightRects },
4759 { "nativeAutoFillForm", "(I)V",
4760 (void*) AutoFillForm },
4761 { "nativeScrollLayer", "(ILandroid/graphics/Rect;)V",
4762 (void*) ScrollRenderLayer },
4763 { "nativeCloseIdleConnections", "()V",
4764 (void*) CloseIdleConnections },
4767 int registerWebViewCore(JNIEnv* env)
4769 jclass widget = env->FindClass("android/webkit/WebViewCore");
4771 "Unable to find class android/webkit/WebViewCore");
4772 gWebViewCoreFields.m_nativeClass = env->GetFieldID(widget, "mNativeClass",
4774 LOG_ASSERT(gWebViewCoreFields.m_nativeClass,
4775 "Unable to find android/webkit/WebViewCore.mNativeClass");
4776 gWebViewCoreFields.m_viewportWidth = env->GetFieldID(widget,
4777 "mViewportWidth", "I");
4778 LOG_ASSERT(gWebViewCoreFields.m_viewportWidth,
4779 "Unable to find android/webkit/WebViewCore.mViewportWidth");
4780 gWebViewCoreFields.m_viewportHeight = env->GetFieldID(widget,
4781 "mViewportHeight", "I");
4782 LOG_ASSERT(gWebViewCoreFields.m_viewportHeight,
4783 "Unable to find android/webkit/WebViewCore.mViewportHeight");
4784 gWebViewCoreFields.m_viewportInitialScale = env->GetFieldID(widget,
4785 "mViewportInitialScale", "I");
4786 LOG_ASSERT(gWebViewCoreFields.m_viewportInitialScale,
4787 "Unable to find android/webkit/WebViewCore.mViewportInitialScale");
4788 gWebViewCoreFields.m_viewportMinimumScale = env->GetFieldID(widget,
4789 "mViewportMinimumScale", "I");
4790 LOG_ASSERT(gWebViewCoreFields.m_viewportMinimumScale,
4791 "Unable to find android/webkit/WebViewCore.mViewportMinimumScale");
4792 gWebViewCoreFields.m_viewportMaximumScale = env->GetFieldID(widget,
4793 "mViewportMaximumScale", "I");
4794 LOG_ASSERT(gWebViewCoreFields.m_viewportMaximumScale,
4795 "Unable to find android/webkit/WebViewCore.mViewportMaximumScale");
4796 gWebViewCoreFields.m_viewportUserScalable = env->GetFieldID(widget,
4797 "mViewportUserScalable", "Z");
4798 LOG_ASSERT(gWebViewCoreFields.m_viewportUserScalable,
4799 "Unable to find android/webkit/WebViewCore.mViewportUserScalable");
4800 gWebViewCoreFields.m_viewportDensityDpi = env->GetFieldID(widget,
4801 "mViewportDensityDpi", "I");
4802 LOG_ASSERT(gWebViewCoreFields.m_viewportDensityDpi,
4803 "Unable to find android/webkit/WebViewCore.mViewportDensityDpi");
4804 gWebViewCoreFields.m_webView = env->GetFieldID(widget,
4805 "mWebView", "Landroid/webkit/WebView;");
4806 LOG_ASSERT(gWebViewCoreFields.m_webView,
4807 "Unable to find android/webkit/WebViewCore.mWebView");
4808 gWebViewCoreFields.m_drawIsPaused = env->GetFieldID(widget,
4809 "mDrawIsPaused", "Z");
4810 LOG_ASSERT(gWebViewCoreFields.m_drawIsPaused,
4811 "Unable to find android/webkit/WebViewCore.mDrawIsPaused");
4812 gWebViewCoreFields.m_lowMemoryUsageMb = env->GetFieldID(widget, "mLowMemoryUsageThresholdMb", "I");
4813 gWebViewCoreFields.m_highMemoryUsageMb = env->GetFieldID(widget, "mHighMemoryUsageThresholdMb", "I");
4814 gWebViewCoreFields.m_highUsageDeltaMb = env->GetFieldID(widget, "mHighUsageDeltaMb", "I");
4816 gWebViewCoreStaticMethods.m_isSupportedMediaMimeType =
4817 env->GetStaticMethodID(widget, "isSupportedMediaMimeType", "(Ljava/lang/String;)Z");
4818 LOG_FATAL_IF(!gWebViewCoreStaticMethods.m_isSupportedMediaMimeType,
4819 "Could not find static method isSupportedMediaMimeType from WebViewCore");
4821 env->DeleteLocalRef(widget);
4823 return jniRegisterNativeMethods(env, "android/webkit/WebViewCore",
4824 gJavaWebViewCoreMethods, NELEM(gJavaWebViewCoreMethods));
4827 } /* namespace android */