diff options
Diffstat (limited to 'Source/WebKit/android/jni/WebViewCore.cpp')
-rw-r--r-- | Source/WebKit/android/jni/WebViewCore.cpp | 3303 |
1 files changed, 1826 insertions, 1477 deletions
diff --git a/Source/WebKit/android/jni/WebViewCore.cpp b/Source/WebKit/android/jni/WebViewCore.cpp index 1b53a6e..f17e573 100644 --- a/Source/WebKit/android/jni/WebViewCore.cpp +++ b/Source/WebKit/android/jni/WebViewCore.cpp @@ -29,10 +29,9 @@ #include "WebViewCore.h" #include "AccessibilityObject.h" +#include "AndroidHitTestResult.h" #include "Attribute.h" -#include "BaseLayerAndroid.h" -#include "CachedNode.h" -#include "CachedRoot.h" +#include "content/address_detector.h" #include "Chrome.h" #include "ChromeClientAndroid.h" #include "ChromiumIncludes.h" @@ -43,6 +42,7 @@ #include "CSSValueKeywords.h" #include "DatabaseTracker.h" #include "Document.h" +#include "DocumentMarkerController.h" #include "DOMWindow.h" #include "DOMSelection.h" #include "Element.h" @@ -53,6 +53,7 @@ #include "ExceptionCode.h" #include "FocusController.h" #include "Font.h" +#include "FontCache.h" #include "Frame.h" #include "FrameLoader.h" #include "FrameLoaderClientAndroid.h" @@ -61,6 +62,7 @@ #include "Geolocation.h" #include "GraphicsContext.h" #include "GraphicsJNI.h" +#include "GraphicsOperationCollection.h" #include "HTMLAnchorElement.h" #include "HTMLAreaElement.h" #include "HTMLElement.h" @@ -78,6 +80,7 @@ #include "HitTestRequest.h" #include "HitTestResult.h" #include "InlineTextBox.h" +#include "KeyboardEvent.h" #include "MemoryUsage.h" #include "NamedNodeMap.h" #include "Navigator.h" @@ -85,6 +88,8 @@ #include "NodeList.h" #include "Page.h" #include "PageGroup.h" +#include "PictureLayerContent.h" +#include "PicturePileLayerContent.h" #include "PlatformKeyboardEvent.h" #include "PlatformString.h" #include "PluginWidgetAndroid.h" @@ -93,6 +98,7 @@ #include "ProgressTracker.h" #include "Range.h" #include "RenderBox.h" +#include "RenderImage.h" #include "RenderInline.h" #include "RenderLayer.h" #include "RenderPart.h" @@ -103,38 +109,43 @@ #include "ResourceRequest.h" #include "RuntimeEnabledFeatures.h" #include "SchemeRegistry.h" +#include "ScopedLocalRef.h" +#include "ScriptController.h" #include "SelectionController.h" +#include "SelectText.h" #include "Settings.h" #include "SkANP.h" #include "SkTemplates.h" #include "SkTDArray.h" #include "SkTypes.h" #include "SkCanvas.h" +#include "SkGraphics.h" #include "SkPicture.h" #include "SkUtils.h" #include "Text.h" +#include "TextIterator.h" +#include "TilesManager.h" #include "TypingCommand.h" #include "WebCache.h" #include "WebCoreFrameBridge.h" +#include "WebCoreJni.h" #include "WebFrameView.h" #include "WindowsKeyboardCodes.h" #include "android_graphics.h" #include "autofill/WebAutofill.h" #include "htmlediting.h" #include "markup.h" +#include "visible_units.h" #include <JNIHelp.h> #include <JNIUtility.h> -#include <ui/KeycodeLabels.h> +#include <androidfw/KeycodeLabels.h> +#include <cutils/properties.h> +#include <v8.h> #include <wtf/CurrentTime.h> #include <wtf/text/AtomicString.h> -#include <wtf/text/StringImpl.h> - -#if USE(V8) -#include "ScriptController.h" -#include "V8Counters.h" #include <wtf/text/CString.h> -#endif +#include <wtf/text/StringImpl.h> #if DEBUG_NAV_UI #include "SkTime.h" @@ -153,34 +164,85 @@ FILE* gDomTreeFile = 0; FILE* gRenderTreeFile = 0; #endif -#ifdef ANDROID_INSTRUMENT -#include "TimeCounter.h" -#endif +#include "BaseLayerAndroid.h" #if USE(ACCELERATED_COMPOSITING) #include "GraphicsLayerAndroid.h" #include "RenderLayerCompositor.h" #endif -#if USE(V8) -#include <v8.h> -#endif +#define FOREGROUND_TIMER_INTERVAL 0.004 // 4ms +#define BACKGROUND_TIMER_INTERVAL 1.0 // 1s -// In some cases, too many invalidations passed to the UI will slow us down. -// Limit ourselves to 32 rectangles, past this just send the area bounds to the UI. -// see WebViewCore::recordPictureSet(). -#define MAX_INVALIDATIONS 32 +// How many ms to wait for the scroll to "settle" before we will consider doing +// prerenders +#define PRERENDER_AFTER_SCROLL_DELAY 750 -/* We pass this flag when recording the actual content, so that we don't spend - time actually regionizing complex path clips, when all we really want to do - is record them. - */ -#define PICT_RECORD_FLAGS SkPicture::kUsePathBoundsForClip_RecordingFlag +#define TOUCH_FLAG_HIT_HANDLER 0x1 +#define TOUCH_FLAG_PREVENT_DEFAULT 0x2 //////////////////////////////////////////////////////////////////////////////////////////////// namespace android { +// Copied from CacheBuilder, not sure if this is needed/correct +IntRect getAreaRect(const HTMLAreaElement* area) +{ + Node* node = area->document(); + while ((node = node->traverseNextNode()) != NULL) { + RenderObject* renderer = node->renderer(); + if (renderer && renderer->isRenderImage()) { + RenderImage* image = static_cast<RenderImage*>(renderer); + HTMLMapElement* map = image->imageMap(); + if (map) { + Node* n; + for (n = map->firstChild(); n; + n = n->traverseNextNode(map)) { + if (n == area) { + if (area->isDefault()) + return image->absoluteBoundingBoxRect(); + return area->computeRect(image); + } + } + } + } + } + return IntRect(); +} + +// Copied from CacheBuilder, not sure if this is needed/correct +// TODO: See if this is even needed (I suspect not), and if not remove it +bool validNode(Frame* startFrame, void* matchFrame, + void* matchNode) +{ + if (matchFrame == startFrame) { + if (matchNode == NULL) + return true; + Node* node = startFrame->document(); + while (node != NULL) { + if (node == matchNode) { + const IntRect& rect = node->hasTagName(HTMLNames::areaTag) ? + getAreaRect(static_cast<HTMLAreaElement*>(node)) : node->getRect(); + // Consider nodes with empty rects that are not at the origin + // to be valid, since news.google.com has valid nodes like this + if (rect.x() == 0 && rect.y() == 0 && rect.isEmpty()) + return false; + return true; + } + node = node->traverseNextNode(); + } + return false; + } + Frame* child = startFrame->tree()->firstChild(); + while (child) { + bool result = validNode(child, matchFrame, matchNode); + if (result) + return result; + child = child->tree()->nextSibling(); + } + return false; +} + static SkTDArray<WebViewCore*> gInstanceList; void WebViewCore::addInstance(WebViewCore* inst) { @@ -189,7 +251,7 @@ void WebViewCore::addInstance(WebViewCore* inst) { void WebViewCore::removeInstance(WebViewCore* inst) { int index = gInstanceList.find(inst); - LOG_ASSERT(index >= 0, "RemoveInstance inst not found"); + ALOG_ASSERT(index >= 0, "RemoveInstance inst not found"); if (index >= 0) { gInstanceList.removeShuffle(index); } @@ -242,8 +304,6 @@ bool WebViewCore::isSupportedMediaMimeType(const WTF::String& mimeType) { // ---------------------------------------------------------------------------- -#define GET_NATIVE_VIEW(env, obj) ((WebViewCore*)env->GetIntField(obj, gWebViewCoreFields.m_nativeClass)) - // Field ids for WebViewCore struct WebViewCoreFields { jfieldID m_nativeClass; @@ -254,7 +314,6 @@ struct WebViewCoreFields { jfieldID m_viewportMaximumScale; jfieldID m_viewportUserScalable; jfieldID m_viewportDensityDpi; - jfieldID m_webView; jfieldID m_drawIsPaused; jfieldID m_lowMemoryUsageMb; jfieldID m_highMemoryUsageMb; @@ -267,7 +326,6 @@ struct WebViewCore::JavaGlue { jweak m_obj; jmethodID m_scrollTo; jmethodID m_contentDraw; - jmethodID m_layersDraw; jmethodID m_requestListBox; jmethodID m_openFileChooser; jmethodID m_requestSingleListBox; @@ -276,17 +334,18 @@ struct WebViewCore::JavaGlue { jmethodID m_jsPrompt; jmethodID m_jsUnload; jmethodID m_jsInterrupt; + jmethodID m_getWebView; jmethodID m_didFirstLayout; jmethodID m_updateViewport; jmethodID m_sendNotifyProgressFinished; jmethodID m_sendViewInvalidate; jmethodID m_updateTextfield; jmethodID m_updateTextSelection; + jmethodID m_updateTextSizeAndScroll; jmethodID m_clearTextEntry; jmethodID m_restoreScale; jmethodID m_needTouchEvents; jmethodID m_requestKeyboard; - jmethodID m_requestKeyboardWithSelection; jmethodID m_exceededDatabaseQuota; jmethodID m_reachedMaxAppCacheSize; jmethodID m_populateVisitedLinks; @@ -295,7 +354,7 @@ struct WebViewCore::JavaGlue { jmethodID m_getDeviceMotionService; jmethodID m_getDeviceOrientationService; jmethodID m_addMessageToConsole; - jmethodID m_formDidBlur; + jmethodID m_focusNodeChanged; jmethodID m_getPluginClass; jmethodID m_showFullScreenPlugin; jmethodID m_hideFullScreenPlugin; @@ -305,14 +364,17 @@ struct WebViewCore::JavaGlue { jmethodID m_destroySurface; jmethodID m_getContext; jmethodID m_keepScreenOn; - jmethodID m_sendFindAgain; jmethodID m_showRect; jmethodID m_centerFitRect; jmethodID m_setScrollbarModes; jmethodID m_setInstallableWebApp; jmethodID m_enterFullscreenForVideoLayer; + jmethodID m_exitFullscreenVideo; jmethodID m_setWebTextViewAutoFillable; jmethodID m_selectAt; + jmethodID m_initEditField; + jmethodID m_chromeCanTakeFocus; + jmethodID m_chromeTakeFocus; AutoJObject object(JNIEnv* env) { // We hold a weak reference to the Java WebViewCore to avoid memeory // leaks due to circular references when WebView.destroy() is not @@ -325,6 +387,23 @@ struct WebViewCore::JavaGlue { } }; +struct WebViewCore::TextFieldInitDataGlue { + jmethodID m_constructor; + jfieldID m_fieldPointer; + jfieldID m_text; + jfieldID m_type; + jfieldID m_isSpellCheckEnabled; + jfieldID m_isTextFieldNext; + jfieldID m_isTextFieldPrev; + jfieldID m_isAutoCompleteEnabled; + jfieldID m_name; + jfieldID m_label; + jfieldID m_maxLength; + jfieldID m_contentBounds; + jfieldID m_nodeLayerId; + jfieldID m_contentRect; +}; + /* * WebViewCore Implementation */ @@ -332,58 +411,37 @@ struct WebViewCore::JavaGlue { static jmethodID GetJMethod(JNIEnv* env, jclass clazz, const char name[], const char signature[]) { jmethodID m = env->GetMethodID(clazz, name, signature); - LOG_ASSERT(m, "Could not find method %s", name); + ALOG_ASSERT(m, "Could not find method %s", name); return m; } -Mutex WebViewCore::gFrameCacheMutex; -Mutex WebViewCore::gCursorBoundsMutex; - WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* mainframe) - : m_frameCacheKit(0) - , m_navPictureKit(0) - , m_moveGeneration(0) - , m_touchGeneration(0) + : m_touchGeneration(0) , m_lastGeneration(0) - , m_updatedFrameCache(true) - , m_findIsUp(false) - , m_hasCursorBounds(false) - , m_cursorBounds(WebCore::IntRect(0, 0, 0, 0)) - , m_cursorHitBounds(WebCore::IntRect(0, 0, 0, 0)) - , m_cursorFrame(0) - , m_cursorLocation(WebCore::IntPoint(0, 0)) - , m_cursorNode(0) , m_javaGlue(new JavaGlue) + , m_textFieldInitDataGlue(new TextFieldInitDataGlue) , m_mainFrame(mainframe) , m_popupReply(0) - , m_lastFocused(0) - , m_lastFocusedBounds(WebCore::IntRect(0,0,0,0)) - , m_blurringNodePointer(0) - , m_lastFocusedSelStart(0) - , m_lastFocusedSelEnd(0) , m_blockTextfieldUpdates(false) , m_focusBoundsChanged(false) , m_skipContentDraw(false) , m_textGeneration(0) - , m_temp(0) - , m_tempPict(0) , m_maxXScroll(320/4) , m_maxYScroll(240/4) , m_scrollOffsetX(0) , m_scrollOffsetY(0) , m_mousePos(WebCore::IntPoint(0,0)) - , m_frameCacheOutOfDate(true) - , m_progressDone(false) , m_screenWidth(320) , m_screenHeight(240) , m_textWrapWidth(320) , m_scale(1.0f) - , m_domtree_version(0) - , m_check_domtree_version(true) , m_groupForVisitedLinks(0) , m_isPaused(false) , m_cacheMode(0) - , m_shouldPaintCaret(true) + , m_fullscreenVideoMode(false) + , m_matchCount(0) + , m_activeMatchIndex(0) + , m_activeMatch(0) , m_pluginInvalTimer(this, &WebViewCore::pluginInvalTimerFired) , m_screenOnCounter(0) , m_currentNodeDomNavigationAxis(0) @@ -391,36 +449,35 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m #if ENABLE(TOUCH_EVENTS) , m_forwardingTouchEvents(false) #endif -#if USE(CHROME_NETWORK_STACK) , m_webRequestContext(0) -#endif + , m_prerenderEnabled(false) { - LOG_ASSERT(m_mainFrame, "Uh oh, somehow a frameview was made without an initial frame!"); + ALOG_ASSERT(m_mainFrame, "Uh oh, somehow a frameview was made without an initial frame!"); jclass clazz = env->GetObjectClass(javaWebViewCore); m_javaGlue->m_obj = env->NewWeakGlobalRef(javaWebViewCore); m_javaGlue->m_scrollTo = GetJMethod(env, clazz, "contentScrollTo", "(IIZZ)V"); m_javaGlue->m_contentDraw = GetJMethod(env, clazz, "contentDraw", "()V"); - m_javaGlue->m_layersDraw = GetJMethod(env, clazz, "layersDraw", "()V"); m_javaGlue->m_requestListBox = GetJMethod(env, clazz, "requestListBox", "([Ljava/lang/String;[I[I)V"); - m_javaGlue->m_openFileChooser = GetJMethod(env, clazz, "openFileChooser", "(Ljava/lang/String;)Ljava/lang/String;"); + m_javaGlue->m_openFileChooser = GetJMethod(env, clazz, "openFileChooser", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"); m_javaGlue->m_requestSingleListBox = GetJMethod(env, clazz, "requestListBox", "([Ljava/lang/String;[II)V"); m_javaGlue->m_jsAlert = GetJMethod(env, clazz, "jsAlert", "(Ljava/lang/String;Ljava/lang/String;)V"); m_javaGlue->m_jsConfirm = GetJMethod(env, clazz, "jsConfirm", "(Ljava/lang/String;Ljava/lang/String;)Z"); m_javaGlue->m_jsPrompt = GetJMethod(env, clazz, "jsPrompt", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"); m_javaGlue->m_jsUnload = GetJMethod(env, clazz, "jsUnload", "(Ljava/lang/String;Ljava/lang/String;)Z"); m_javaGlue->m_jsInterrupt = GetJMethod(env, clazz, "jsInterrupt", "()Z"); + m_javaGlue->m_getWebView = GetJMethod(env, clazz, "getWebView", "()Landroid/webkit/WebView;"); m_javaGlue->m_didFirstLayout = GetJMethod(env, clazz, "didFirstLayout", "(Z)V"); m_javaGlue->m_updateViewport = GetJMethod(env, clazz, "updateViewport", "()V"); m_javaGlue->m_sendNotifyProgressFinished = GetJMethod(env, clazz, "sendNotifyProgressFinished", "()V"); m_javaGlue->m_sendViewInvalidate = GetJMethod(env, clazz, "sendViewInvalidate", "(IIII)V"); m_javaGlue->m_updateTextfield = GetJMethod(env, clazz, "updateTextfield", "(IZLjava/lang/String;I)V"); - m_javaGlue->m_updateTextSelection = GetJMethod(env, clazz, "updateTextSelection", "(IIII)V"); + m_javaGlue->m_updateTextSelection = GetJMethod(env, clazz, "updateTextSelection", "(IIIII)V"); + m_javaGlue->m_updateTextSizeAndScroll = GetJMethod(env, clazz, "updateTextSizeAndScroll", "(IIIII)V"); m_javaGlue->m_clearTextEntry = GetJMethod(env, clazz, "clearTextEntry", "()V"); m_javaGlue->m_restoreScale = GetJMethod(env, clazz, "restoreScale", "(FF)V"); m_javaGlue->m_needTouchEvents = GetJMethod(env, clazz, "needTouchEvents", "(Z)V"); m_javaGlue->m_requestKeyboard = GetJMethod(env, clazz, "requestKeyboard", "(Z)V"); - m_javaGlue->m_requestKeyboardWithSelection = GetJMethod(env, clazz, "requestKeyboardWithSelection", "(IIII)V"); m_javaGlue->m_exceededDatabaseQuota = GetJMethod(env, clazz, "exceededDatabaseQuota", "(Ljava/lang/String;Ljava/lang/String;JJ)V"); m_javaGlue->m_reachedMaxAppCacheSize = GetJMethod(env, clazz, "reachedMaxAppCacheSize", "(J)V"); m_javaGlue->m_populateVisitedLinks = GetJMethod(env, clazz, "populateVisitedLinks", "()V"); @@ -429,7 +486,7 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m m_javaGlue->m_getDeviceMotionService = GetJMethod(env, clazz, "getDeviceMotionService", "()Landroid/webkit/DeviceMotionService;"); m_javaGlue->m_getDeviceOrientationService = GetJMethod(env, clazz, "getDeviceOrientationService", "()Landroid/webkit/DeviceOrientationService;"); m_javaGlue->m_addMessageToConsole = GetJMethod(env, clazz, "addMessageToConsole", "(Ljava/lang/String;ILjava/lang/String;I)V"); - m_javaGlue->m_formDidBlur = GetJMethod(env, clazz, "formDidBlur", "(I)V"); + m_javaGlue->m_focusNodeChanged = GetJMethod(env, clazz, "focusNodeChanged", "(ILandroid/webkit/WebViewCore$WebKitHitTest;)V"); m_javaGlue->m_getPluginClass = GetJMethod(env, clazz, "getPluginClass", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Class;"); m_javaGlue->m_showFullScreenPlugin = GetJMethod(env, clazz, "showFullScreenPlugin", "(Landroid/webkit/ViewManager$ChildView;II)V"); m_javaGlue->m_hideFullScreenPlugin = GetJMethod(env, clazz, "hideFullScreenPlugin", "()V"); @@ -439,20 +496,40 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m m_javaGlue->m_destroySurface = GetJMethod(env, clazz, "destroySurface", "(Landroid/webkit/ViewManager$ChildView;)V"); m_javaGlue->m_getContext = GetJMethod(env, clazz, "getContext", "()Landroid/content/Context;"); m_javaGlue->m_keepScreenOn = GetJMethod(env, clazz, "keepScreenOn", "(Z)V"); - m_javaGlue->m_sendFindAgain = GetJMethod(env, clazz, "sendFindAgain", "()V"); m_javaGlue->m_showRect = GetJMethod(env, clazz, "showRect", "(IIIIIIFFFF)V"); m_javaGlue->m_centerFitRect = GetJMethod(env, clazz, "centerFitRect", "(IIII)V"); m_javaGlue->m_setScrollbarModes = GetJMethod(env, clazz, "setScrollbarModes", "(II)V"); m_javaGlue->m_setInstallableWebApp = GetJMethod(env, clazz, "setInstallableWebApp", "()V"); #if ENABLE(VIDEO) m_javaGlue->m_enterFullscreenForVideoLayer = GetJMethod(env, clazz, "enterFullscreenForVideoLayer", "(ILjava/lang/String;)V"); + m_javaGlue->m_exitFullscreenVideo = GetJMethod(env, clazz, "exitFullscreenVideo", "()V"); #endif m_javaGlue->m_setWebTextViewAutoFillable = GetJMethod(env, clazz, "setWebTextViewAutoFillable", "(ILjava/lang/String;)V"); m_javaGlue->m_selectAt = GetJMethod(env, clazz, "selectAt", "(II)V"); + m_javaGlue->m_initEditField = GetJMethod(env, clazz, "initEditField", "(IIILandroid/webkit/WebViewCore$TextFieldInitData;)V"); + m_javaGlue->m_chromeCanTakeFocus = GetJMethod(env, clazz, "chromeCanTakeFocus", "(I)Z"); + m_javaGlue->m_chromeTakeFocus = GetJMethod(env, clazz, "chromeTakeFocus", "(I)V"); env->DeleteLocalRef(clazz); env->SetIntField(javaWebViewCore, gWebViewCoreFields.m_nativeClass, (jint)this); + jclass tfidClazz = env->FindClass("android/webkit/WebViewCore$TextFieldInitData"); + m_textFieldInitDataGlue->m_fieldPointer = env->GetFieldID(tfidClazz, "mFieldPointer", "I"); + m_textFieldInitDataGlue->m_text = env->GetFieldID(tfidClazz, "mText", "Ljava/lang/String;"); + m_textFieldInitDataGlue->m_type = env->GetFieldID(tfidClazz, "mType", "I"); + m_textFieldInitDataGlue->m_isSpellCheckEnabled = env->GetFieldID(tfidClazz, "mIsSpellCheckEnabled", "Z"); + m_textFieldInitDataGlue->m_isTextFieldNext = env->GetFieldID(tfidClazz, "mIsTextFieldNext", "Z"); + m_textFieldInitDataGlue->m_isTextFieldPrev = env->GetFieldID(tfidClazz, "mIsTextFieldPrev", "Z"); + m_textFieldInitDataGlue->m_isAutoCompleteEnabled = env->GetFieldID(tfidClazz, "mIsAutoCompleteEnabled", "Z"); + m_textFieldInitDataGlue->m_name = env->GetFieldID(tfidClazz, "mName", "Ljava/lang/String;"); + m_textFieldInitDataGlue->m_label = env->GetFieldID(tfidClazz, "mLabel", "Ljava/lang/String;"); + m_textFieldInitDataGlue->m_maxLength = env->GetFieldID(tfidClazz, "mMaxLength", "I"); + m_textFieldInitDataGlue->m_contentBounds = env->GetFieldID(tfidClazz, "mContentBounds", "Landroid/graphics/Rect;"); + m_textFieldInitDataGlue->m_nodeLayerId = env->GetFieldID(tfidClazz, "mNodeLayerId", "I"); + m_textFieldInitDataGlue->m_contentRect = env->GetFieldID(tfidClazz, "mContentRect", "Landroid/graphics/Rect;"); + m_textFieldInitDataGlue->m_constructor = GetJMethod(env, tfidClazz, "<init>", "()V"); + env->DeleteLocalRef(tfidClazz); + PageGroup::setShouldTrackVisitedLinks(true); clearContent(); @@ -463,22 +540,23 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m WebViewCore::addInstance(this); -#if USE(CHROME_NETWORK_STACK) AndroidNetworkLibraryImpl::InitWithApplicationContext(env, 0); -#endif -#if USE(V8) + // increase the font cache size beyond the standard system setting + SkGraphics::SetFontCacheLimit(1572864); // 1572864 bytes == 1.5 MB + // Static initialisation of certain important V8 static data gets performed at system startup when // libwebcore gets loaded. We now need to associate the WebCore thread with V8 to complete // initialisation. v8::V8::Initialize(); -#endif // Configure any RuntimeEnabled features that we need to change from their default now. // See WebCore/bindings/generic/RuntimeEnabledFeatures.h // HTML5 History API RuntimeEnabledFeatures::setPushStateEnabled(true); + if (m_mainFrame) + m_mainFrame->settings()->setMinDOMTimerInterval(FOREGROUND_TIMER_INTERVAL); } WebViewCore::~WebViewCore() @@ -494,24 +572,40 @@ WebViewCore::~WebViewCore() m_javaGlue->m_obj = 0; } delete m_javaGlue; - delete m_frameCacheKit; - delete m_navPictureKit; } WebViewCore* WebViewCore::getWebViewCore(const WebCore::FrameView* view) { - return getWebViewCore(static_cast<const WebCore::ScrollView*>(view)); + if (!view) + return 0; + if (view->platformWidget()) + return static_cast<WebFrameView*>(view->platformWidget())->webViewCore(); + Frame* frame = view->frame(); + while (Frame* parent = frame->tree()->parent()) + frame = parent; + WebFrameView* webFrameView = 0; + if (frame && frame->view()) + webFrameView = static_cast<WebFrameView*>(frame->view()->platformWidget()); + if (!webFrameView) + return 0; + return webFrameView->webViewCore(); } WebViewCore* WebViewCore::getWebViewCore(const WebCore::ScrollView* view) { if (!view) return 0; - - WebFrameView* webFrameView = static_cast<WebFrameView*>(view->platformWidget()); - if (!webFrameView) - return 0; - return webFrameView->webViewCore(); + if (view->platformWidget()) + return static_cast<WebFrameView*>(view->platformWidget())->webViewCore(); + const FrameView* frameView = 0; + if (view->isFrameView()) + frameView = static_cast<const FrameView*>(view); + else { + frameView = static_cast<const FrameView*>(view->root()); + if (!frameView) + return 0; + } + return getWebViewCore(frameView); } static bool layoutIfNeededRecursive(WebCore::Frame* f) @@ -522,84 +616,35 @@ static bool layoutIfNeededRecursive(WebCore::Frame* f) WebCore::FrameView* v = f->view(); if (!v) return true; - - if (v->needsLayout()) - v->layout(f->tree()->parent()); - - WebCore::Frame* child = f->tree()->firstChild(); - bool success = true; - while (child) { - success &= layoutIfNeededRecursive(child); - child = child->tree()->nextSibling(); - } - - return success && !v->needsLayout(); -} - -CacheBuilder& WebViewCore::cacheBuilder() -{ - return FrameLoaderClientAndroid::get(m_mainFrame)->getCacheBuilder(); + v->updateLayoutAndStyleIfNeededRecursive(); + return !v->needsLayout(); } WebCore::Node* WebViewCore::currentFocus() { - return cacheBuilder().currentFocus(); + return focusedFrame()->document()->focusedNode(); } -void WebViewCore::recordPicture(SkPicture* picture) +void WebViewCore::layout() { - // if there is no document yet, just return - if (!m_mainFrame->document()) { - DBG_NAV_LOG("no document"); - return; - } - // Call layout to ensure that the contentWidth and contentHeight are correct - if (!layoutIfNeededRecursive(m_mainFrame)) { - DBG_NAV_LOG("layout failed"); - return; - } - // draw into the picture's recording canvas - WebCore::FrameView* view = m_mainFrame->view(); - DBG_NAV_LOGD("view=(w=%d,h=%d)", view->contentsWidth(), - view->contentsHeight()); - SkAutoPictureRecord arp(picture, view->contentsWidth(), - view->contentsHeight(), PICT_RECORD_FLAGS); - SkAutoMemoryUsageProbe mup(__FUNCTION__); - - WebCore::PlatformGraphicsContext pgc(arp.getRecordingCanvas()); - WebCore::GraphicsContext gc(&pgc); - view->platformWidget()->draw(&gc, WebCore::IntRect(0, 0, - view->contentsWidth(), view->contentsHeight())); -} + TRACE_METHOD(); -void WebViewCore::recordPictureSet(PictureSet* content) -{ // if there is no document yet, just return if (!m_mainFrame->document()) { - DBG_SET_LOG("!m_mainFrame->document()"); - return; - } - if (m_addInval.isEmpty()) { - DBG_SET_LOG("m_addInval.isEmpty()"); + ALOGV("!m_mainFrame->document()"); return; } + // Call layout to ensure that the contentWidth and contentHeight are correct // it's fine for layout to gather invalidates, but defeat sending a message // back to java to call webkitDraw, since we're already in the middle of // doing that - m_skipContentDraw = true; bool success = layoutIfNeededRecursive(m_mainFrame); - m_skipContentDraw = false; // We may be mid-layout and thus cannot draw. if (!success) return; - { // collect WebViewCoreRecordTimeCounter after layoutIfNeededRecursive -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreRecordTimeCounter); -#endif - // if the webkit page dimensions changed, discard the pictureset and redraw. WebCore::FrameView* view = m_mainFrame->view(); int width = view->contentsWidth(); @@ -650,6 +695,8 @@ void WebViewCore::recordPictureSet(PictureSet* content) // If the new total is larger than the content, resize the view to include // all the content. if (!contentRect.contains(total)) { + // TODO: Does this ever happen? Is this needed now that we don't flatten + // frames? // Resize the view to change the overflow clip. view->resize(total.fRight, total.fBottom); @@ -658,159 +705,27 @@ void WebViewCore::recordPictureSet(PictureSet* content) view->forceLayout(); // Relayout similar to above - m_skipContentDraw = true; - bool success = layoutIfNeededRecursive(m_mainFrame); - m_skipContentDraw = false; - if (!success) - return; - - // Set the computed content width - width = view->contentsWidth(); - height = view->contentsHeight(); + layoutIfNeededRecursive(m_mainFrame); } +} - if (cacheBuilder().pictureSetDisabled()) - content->clear(); - -#if USE(ACCELERATED_COMPOSITING) - // The invals are not always correct when the content size has changed. For - // now, let's just reset the inval so that it invalidates the entire content - // -- the pictureset will be fully repainted, tiles will be marked dirty and - // will have to be repainted. - - // FIXME: the webkit invals ought to have been enough... - if (content->width() != width || content->height() != height) { - SkIRect r; - r.fLeft = 0; - r.fTop = 0; - r.fRight = width; - r.fBottom = height; - m_addInval.setRect(r); - } -#endif - - content->setDimensions(width, height, &m_addInval); - - // Add the current inval rects to the PictureSet, and rebuild it. - content->add(m_addInval, 0, 0, false); +void WebViewCore::recordPicturePile() +{ + // if the webkit page dimensions changed, discard the pictureset and redraw. + WebCore::FrameView* view = m_mainFrame->view(); + int width = view ? view->contentsWidth() : 0; + int height = view ? view->contentsHeight() : 0; - // If we have too many invalidations, just get the area bounds - SkRegion::Iterator iterator(m_addInval); - int nbInvals = 0; - while (!iterator.done()) { - iterator.next(); - nbInvals++; - if (nbInvals > MAX_INVALIDATIONS) - break; - } - if (nbInvals > MAX_INVALIDATIONS) { - SkIRect r = m_addInval.getBounds(); - m_addInval.setRect(r); - } + m_content.setSize(IntSize(width, height)); // Rebuild the pictureset (webkit repaint) - rebuildPictureSet(content); - } // WebViewCoreRecordTimeCounter - - WebCore::Node* oldFocusNode = currentFocus(); - m_frameCacheOutOfDate = true; - WebCore::IntRect oldBounds; - int oldSelStart = 0; - int oldSelEnd = 0; - if (oldFocusNode) { - oldBounds = oldFocusNode->getRect(); - RenderObject* renderer = oldFocusNode->renderer(); - if (renderer && (renderer->isTextArea() || renderer->isTextField())) { - WebCore::RenderTextControl* rtc = - static_cast<WebCore::RenderTextControl*>(renderer); - oldSelStart = rtc->selectionStart(); - oldSelEnd = rtc->selectionEnd(); - } - } else - oldBounds = WebCore::IntRect(0,0,0,0); - unsigned latestVersion = 0; - if (m_check_domtree_version) { - // as domTreeVersion only increment, we can just check the sum to see - // whether we need to update the frame cache - for (Frame* frame = m_mainFrame; frame; frame = frame->tree()->traverseNext()) { - const Document* doc = frame->document(); - latestVersion += doc->domTreeVersion() + doc->styleVersion(); - } - } - DBG_NAV_LOGD("m_lastFocused=%p oldFocusNode=%p" - " m_lastFocusedBounds={%d,%d,%d,%d} oldBounds={%d,%d,%d,%d}" - " m_lastFocusedSelection={%d,%d} oldSelection={%d,%d}" - " m_check_domtree_version=%s latestVersion=%d m_domtree_version=%d", - m_lastFocused, oldFocusNode, - m_lastFocusedBounds.x(), m_lastFocusedBounds.y(), - m_lastFocusedBounds.width(), m_lastFocusedBounds.height(), - oldBounds.x(), oldBounds.y(), oldBounds.width(), oldBounds.height(), - m_lastFocusedSelStart, m_lastFocusedSelEnd, oldSelStart, oldSelEnd, - m_check_domtree_version ? "true" : "false", - latestVersion, m_domtree_version); - if (m_lastFocused == oldFocusNode && m_lastFocusedBounds == oldBounds - && m_lastFocusedSelStart == oldSelStart - && m_lastFocusedSelEnd == oldSelEnd - && !m_findIsUp - && (!m_check_domtree_version || latestVersion == m_domtree_version)) - { - return; - } - m_focusBoundsChanged |= m_lastFocused == oldFocusNode - && m_lastFocusedBounds != oldBounds; - m_lastFocused = oldFocusNode; - m_lastFocusedBounds = oldBounds; - m_lastFocusedSelStart = oldSelStart; - m_lastFocusedSelEnd = oldSelEnd; - m_domtree_version = latestVersion; - DBG_NAV_LOG("call updateFrameCache"); - updateFrameCache(); - if (m_findIsUp) { - LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); - JNIEnv* env = JSC::Bindings::getJNIEnv(); - AutoJObject javaObject = m_javaGlue->object(env); - if (javaObject.get()) { - env->CallVoidMethod(javaObject.get(), m_javaGlue->m_sendFindAgain); - checkException(env); - } - } -} - -// note: updateCursorBounds is called directly by the WebView thread -// This needs to be called each time we call CachedRoot::setCursor() with -// non-null CachedNode/CachedFrame, since otherwise the WebViewCore's data -// about the cursor is incorrect. When we call setCursor(0,0), we need -// to set hasCursorBounds to false. -void WebViewCore::updateCursorBounds(const CachedRoot* root, - const CachedFrame* cachedFrame, const CachedNode* cachedNode) -{ - LOG_ASSERT(root, "updateCursorBounds: root cannot be null"); - LOG_ASSERT(cachedNode, "updateCursorBounds: cachedNode cannot be null"); - LOG_ASSERT(cachedFrame, "updateCursorBounds: cachedFrame cannot be null"); - gCursorBoundsMutex.lock(); - m_hasCursorBounds = !cachedNode->isHidden(); - // If m_hasCursorBounds is false, we never look at the other - // values, so do not bother setting them. - if (m_hasCursorBounds) { - WebCore::IntRect bounds = cachedNode->bounds(cachedFrame); - if (m_cursorBounds != bounds) - DBG_NAV_LOGD("new cursor bounds=(%d,%d,w=%d,h=%d)", - bounds.x(), bounds.y(), bounds.width(), bounds.height()); - m_cursorBounds = bounds; - m_cursorHitBounds = cachedNode->hitBounds(cachedFrame); - m_cursorFrame = cachedFrame->framePointer(); - root->getSimulatedMousePosition(&m_cursorLocation); - m_cursorNode = cachedNode->nodePointer(); - } - gCursorBoundsMutex.unlock(); + m_content.updatePicturesIfNeeded(this); } void WebViewCore::clearContent() { - DBG_SET_LOG(""); - m_content.clear(); - m_addInval.setEmpty(); - m_rebuildInval.setEmpty(); + m_content.reset(); + updateLocale(); } bool WebViewCore::focusBoundsChanged() @@ -820,75 +735,82 @@ bool WebViewCore::focusBoundsChanged() return result; } -SkPicture* WebViewCore::rebuildPicture(const SkIRect& inval) +void WebViewCore::paintContents(WebCore::GraphicsContext* gc, WebCore::IntRect& dirty) { WebCore::FrameView* view = m_mainFrame->view(); - int width = view->contentsWidth(); - int height = view->contentsHeight(); - SkPicture* picture = new SkPicture(); - SkAutoPictureRecord arp(picture, width, height, PICT_RECORD_FLAGS); - SkAutoMemoryUsageProbe mup(__FUNCTION__); - SkCanvas* recordingCanvas = arp.getRecordingCanvas(); + if (!view) { + gc->setFillColor(WebCore::Color::white, WebCore::ColorSpaceDeviceRGB); + gc->fillColor(); + return; + } - WebCore::PlatformGraphicsContext pgc(recordingCanvas); - WebCore::GraphicsContext gc(&pgc); IntPoint origin = view->minimumScrollPosition(); - WebCore::IntRect drawArea(inval.fLeft + origin.x(), inval.fTop + origin.y(), - inval.width(), inval.height()); - recordingCanvas->translate(-drawArea.x(), -drawArea.y()); - recordingCanvas->save(); - view->platformWidget()->draw(&gc, drawArea); - m_rebuildInval.op(inval, SkRegion::kUnion_Op); - DBG_SET_LOGD("m_rebuildInval={%d,%d,r=%d,b=%d}", - m_rebuildInval.getBounds().fLeft, m_rebuildInval.getBounds().fTop, - m_rebuildInval.getBounds().fRight, m_rebuildInval.getBounds().fBottom); - - return picture; + IntRect drawArea = dirty; + gc->translate(-origin.x(), -origin.y()); + drawArea.move(origin.x(), origin.y()); + view->platformWidget()->draw(gc, drawArea); } -void WebViewCore::rebuildPictureSet(PictureSet* pictureSet) +void WebViewCore::setPrerenderingEnabled(bool enable) { - WebCore::FrameView* view = m_mainFrame->view(); - -#ifdef FAST_PICTURESET - WTF::Vector<Bucket*>* buckets = pictureSet->bucketsToUpdate(); - - for (unsigned int i = 0; i < buckets->size(); i++) { - Bucket* bucket = (*buckets)[i]; - for (unsigned int j = 0; j < bucket->size(); j++) { - BucketPicture& bucketPicture = (*bucket)[j]; - const SkIRect& inval = bucketPicture.mRealArea; - SkPicture* picture = rebuildPicture(inval); - SkSafeUnref(bucketPicture.mPicture); - bucketPicture.mPicture = picture; - } - } - buckets->clear(); -#else - size_t size = pictureSet->size(); - for (size_t index = 0; index < size; index++) { - if (pictureSet->upToDate(index)) - continue; - const SkIRect& inval = pictureSet->bounds(index); - DBG_SET_LOGD("pictSet=%p [%d] {%d,%d,w=%d,h=%d}", pictureSet, index, - inval.fLeft, inval.fTop, inval.width(), inval.height()); - pictureSet->setPicture(index, rebuildPicture(inval)); - } + MutexLocker locker(m_prerenderLock); + m_prerenderEnabled = enable; +} - pictureSet->validate(__FUNCTION__); -#endif +bool WebViewCore::prerenderingEnabled() +{ + MutexLocker locker(m_prerenderLock); + return m_prerenderEnabled; } -bool WebViewCore::updateLayers(LayerAndroid* layers) +SkCanvas* WebViewCore::createPrerenderCanvas(PrerenderedInval* prerendered) { - // We update the layers - ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(m_mainFrame->page()->chrome()->client()); - GraphicsLayerAndroid* root = static_cast<GraphicsLayerAndroid*>(chromeC->layersSync()); - if (root) { - LayerAndroid* updatedLayer = root->contentLayer(); - return layers->updateWithTree(updatedLayer); - } - return true; + // Has WebView disabled prerenders (not attached, etc...)? + if (!prerenderingEnabled()) + return 0; + // Does this WebView have focus? + if (!m_mainFrame->page()->focusController()->isActive()) + return 0; + // Are we scrolling? + if (currentTimeMS() - m_scrollSetTime < PRERENDER_AFTER_SCROLL_DELAY) + return 0; + // Do we have anything to render? + if (prerendered->area.isEmpty()) + return 0; + FloatRect scaleTemp(m_scrollOffsetX, m_scrollOffsetY, m_screenWidth, m_screenHeight); + scaleTemp.scale(m_scale); + IntRect visibleTileClip = enclosingIntRect(scaleTemp); + FloatRect scaledArea = prerendered->area; + scaledArea.scale(m_scale); + IntRect enclosingScaledArea = enclosingIntRect(scaledArea); + if (enclosingScaledArea.isEmpty()) + return 0; + // "round out" the screen to tile boundaries so that we can clip yet still + // cover any visible tiles with the prerender + int tw = TilesManager::tileWidth(); + int th = TilesManager::tileHeight(); + float left = tw * (int) (visibleTileClip.x() / tw); + float top = th * (int) (visibleTileClip.y() / th); + float right = tw * (int) ceilf(visibleTileClip.maxX() / (float) tw); + float bottom = th * (int) ceilf(visibleTileClip.maxY() / (float) th); + visibleTileClip = IntRect(left, top, right - left, bottom - top); + enclosingScaledArea.intersect(visibleTileClip); + if (enclosingScaledArea.isEmpty()) + return 0; + prerendered->screenArea = enclosingScaledArea; + FloatRect enclosingDocArea(enclosingScaledArea); + enclosingDocArea.scale(1 / m_scale); + prerendered->area = enclosingIntRect(enclosingDocArea); + if (prerendered->area.isEmpty()) + return 0; + prerendered->bitmap.setConfig(SkBitmap::kARGB_8888_Config, + enclosingScaledArea.width(), + enclosingScaledArea.height()); + prerendered->bitmap.allocPixels(); + SkCanvas* bitmapCanvas = new SkCanvas(prerendered->bitmap); + bitmapCanvas->scale(m_scale, m_scale); + bitmapCanvas->translate(-enclosingDocArea.x(), -enclosingDocArea.y()); + return bitmapCanvas; } void WebViewCore::notifyAnimationStarted() @@ -902,93 +824,113 @@ void WebViewCore::notifyAnimationStarted() } -BaseLayerAndroid* WebViewCore::createBaseLayer(SkRegion* region) +BaseLayerAndroid* WebViewCore::createBaseLayer(GraphicsLayerAndroid* root) { - BaseLayerAndroid* base = new BaseLayerAndroid(); - base->setContent(m_content); + // We set the background color + Color background = Color::white; - m_skipContentDraw = true; - bool layoutSucceeded = layoutIfNeededRecursive(m_mainFrame); - m_skipContentDraw = false; - // Layout only fails if called during a layout. - LOG_ASSERT(layoutSucceeded, "Can never be called recursively"); + bool bodyHasFixedBackgroundImage = false; + bool bodyHasCSSBackground = false; -#if USE(ACCELERATED_COMPOSITING) - // We set the background color if (m_mainFrame && m_mainFrame->document() && m_mainFrame->document()->body()) { + Document* document = m_mainFrame->document(); RefPtr<RenderStyle> style = document->styleForElementIgnoringPendingStylesheets(document->body()); if (style->hasBackground()) { - Color color = style->visitedDependentColor(CSSPropertyBackgroundColor); - if (color.isValid() && color.alpha() > 0) - base->setBackgroundColor(color); + background = style->visitedDependentColor(CSSPropertyBackgroundColor); + bodyHasCSSBackground = true; + } + WebCore::FrameView* view = m_mainFrame->view(); + if (view) { + Color viewBackground = view->baseBackgroundColor(); + background = bodyHasCSSBackground ? viewBackground.blend(background) : viewBackground; } + if (style->hasFixedBackgroundImage()) { + Image* backgroundImage = FixedBackgroundImageLayerAndroid::GetCachedImage(style); + if (backgroundImage && backgroundImage->width() > 1 && backgroundImage->height() > 1) + bodyHasFixedBackgroundImage = true; + } + } + + PicturePileLayerContent* content = new PicturePileLayerContent(m_content); + m_content.clearPrerenders(); + + BaseLayerAndroid* realBase = 0; + LayerAndroid* base = 0; + + //If we have a fixed background image on the body element, the fixed image + // will be contained in the PictureSet (the content object), and the foreground + //of the body element will be moved to a layer. + //In that case, let's change the hierarchy to obtain: + // + //BaseLayerAndroid + // \- FixedBackgroundBaseLayerAndroid (fixed positioning) + // \- ForegroundBaseLayerAndroid + // \- root layer (webkit composited tree) + + if (bodyHasFixedBackgroundImage) { + base = new ForegroundBaseLayerAndroid(0); + base->setSize(content->width(), content->height()); + + Document* document = m_mainFrame->document(); + RefPtr<RenderStyle> style = document->styleForElementIgnoringPendingStylesheets(document->body()); + + FixedBackgroundImageLayerAndroid* baseBackground = + new FixedBackgroundImageLayerAndroid(style, content->width(), content->height()); + + realBase = new BaseLayerAndroid(0); + realBase->setSize(content->width(), content->height()); + realBase->addChild(baseBackground); + realBase->addChild(base); + baseBackground->unref(); + base->unref(); + } else { + realBase = new BaseLayerAndroid(content); + base = realBase; } + realBase->setBackgroundColor(background); + + SkSafeUnref(content); + // We update the layers - ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(m_mainFrame->page()->chrome()->client()); - GraphicsLayerAndroid* root = static_cast<GraphicsLayerAndroid*>(chromeC->layersSync()); if (root) { LayerAndroid* copyLayer = new LayerAndroid(*root->contentLayer()); base->addChild(copyLayer); copyLayer->unref(); root->contentLayer()->clearDirtyRegion(); } -#endif - return base; + return realBase; } -BaseLayerAndroid* WebViewCore::recordContent(SkRegion* region, SkIPoint* point) +BaseLayerAndroid* WebViewCore::recordContent(SkIPoint* point) { - DBG_SET_LOG("start"); - // If there is a pending style recalculation, just return. - if (m_mainFrame->document()->isPendingStyleRecalc()) { - DBG_SET_LOGD("recordContent: pending style recalc, ignoring."); - return 0; - } - float progress = (float) m_mainFrame->page()->progress()->estimatedProgress(); - m_progressDone = progress <= 0.0f || progress >= 1.0f; - recordPictureSet(&m_content); - if (!m_progressDone && m_content.isEmpty()) { - DBG_SET_LOGD("empty (progress=%g)", progress); - return 0; - } - region->set(m_addInval); - m_addInval.setEmpty(); + m_skipContentDraw = true; + layout(); + ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(m_mainFrame->page()->chrome()->client()); + GraphicsLayerAndroid* root = static_cast<GraphicsLayerAndroid*>(chromeC->layersSync()); + m_skipContentDraw = false; + recordPicturePile(); + + BaseLayerAndroid* baseLayer = createBaseLayer(root); + + baseLayer->markAsDirty(m_content.dirtyRegion()); + m_content.dirtyRegion().setEmpty(); #if USE(ACCELERATED_COMPOSITING) #else - region->op(m_rebuildInval, SkRegion::kUnion_Op); + baseLayer->markAsDirty(m_rebuildInval); #endif - m_rebuildInval.setEmpty(); - point->fX = m_content.width(); - point->fY = m_content.height(); - DBG_SET_LOGD("region={%d,%d,r=%d,b=%d}", region->getBounds().fLeft, - region->getBounds().fTop, region->getBounds().fRight, - region->getBounds().fBottom); - DBG_SET_LOG("end"); + point->fX = m_content.size().width(); + point->fY = m_content.size().height(); - return createBaseLayer(region); -} - -void WebViewCore::splitContent(PictureSet* content) -{ -#ifdef FAST_PICTURESET -#else - bool layoutSucceeded = layoutIfNeededRecursive(m_mainFrame); - LOG_ASSERT(layoutSucceeded, "Can never be called recursively"); - content->split(&m_content); - rebuildPictureSet(&m_content); - content->set(m_content); -#endif // FAST_PICTURESET + return baseLayer; } void WebViewCore::scrollTo(int x, int y, bool animate) { - LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); - -// LOGD("WebViewCore::scrollTo(%d %d)\n", x, y); + ALOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); JNIEnv* env = JSC::Bindings::getJNIEnv(); AutoJObject javaObject = m_javaGlue->object(env); @@ -1001,7 +943,7 @@ void WebViewCore::scrollTo(int x, int y, bool animate) void WebViewCore::sendNotifyProgressFinished() { - LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); + ALOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); JNIEnv* env = JSC::Bindings::getJNIEnv(); AutoJObject javaObject = m_javaGlue->object(env); if (!javaObject.get()) @@ -1012,7 +954,7 @@ void WebViewCore::sendNotifyProgressFinished() void WebViewCore::viewInvalidate(const WebCore::IntRect& rect) { - LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); + ALOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); JNIEnv* env = JSC::Bindings::getJNIEnv(); AutoJObject javaObject = m_javaGlue->object(env); if (!javaObject.get()) @@ -1033,26 +975,12 @@ void WebViewCore::contentDraw() checkException(env); } -void WebViewCore::layersDraw() -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - AutoJObject javaObject = m_javaGlue->object(env); - if (!javaObject.get()) - return; - env->CallVoidMethod(javaObject.get(), m_javaGlue->m_layersDraw); - checkException(env); -} - void WebViewCore::contentInvalidate(const WebCore::IntRect &r) { - DBG_SET_LOGD("rect={%d,%d,w=%d,h=%d}", r.x(), r.y(), r.width(), r.height()); - SkIRect rect(r); - if (!rect.intersect(0, 0, INT_MAX, INT_MAX)) - return; - m_addInval.op(rect, SkRegion::kUnion_Op); - DBG_SET_LOGD("m_addInval={%d,%d,r=%d,b=%d}", - m_addInval.getBounds().fLeft, m_addInval.getBounds().fTop, - m_addInval.getBounds().fRight, m_addInval.getBounds().fBottom); + IntPoint origin = m_mainFrame->view()->minimumScrollPosition(); + IntRect dirty = r; + dirty.move(-origin.x(), -origin.y()); + m_content.invalidate(dirty); if (!m_skipContentDraw) contentDraw(); } @@ -1072,19 +1000,9 @@ void WebViewCore::offInvalidate(const WebCore::IntRect &r) contentInvalidate(r); } -static int pin_pos(int x, int width, int targetWidth) -{ - if (x + width > targetWidth) - x = targetWidth - width; - if (x < 0) - x = 0; - return x; -} - void WebViewCore::didFirstLayout() { - DEBUG_NAV_UI_LOGD("%s", __FUNCTION__); - LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); + ALOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); JNIEnv* env = JSC::Bindings::getJNIEnv(); AutoJObject javaObject = m_javaGlue->object(env); @@ -1094,7 +1012,7 @@ void WebViewCore::didFirstLayout() const WebCore::KURL& url = m_mainFrame->document()->url(); if (url.isEmpty()) return; - LOGV("::WebCore:: didFirstLayout %s", url.string().ascii().data()); + ALOGV("::WebCore:: didFirstLayout %s", url.string().ascii().data()); WebCore::FrameLoadType loadType = m_mainFrame->loader()->loadType(); @@ -1108,17 +1026,11 @@ void WebViewCore::didFirstLayout() // a newly-loaded page. || loadType == WebCore::FrameLoadTypeSame); checkException(env); - - DBG_NAV_LOG("call updateFrameCache"); - m_check_domtree_version = false; - updateFrameCache(); - m_history.setDidFirstLayout(true); } void WebViewCore::updateViewport() { - DEBUG_NAV_UI_LOGD("%s", __FUNCTION__); - LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); + ALOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); JNIEnv* env = JSC::Bindings::getJNIEnv(); AutoJObject javaObject = m_javaGlue->object(env); @@ -1130,8 +1042,7 @@ void WebViewCore::updateViewport() void WebViewCore::restoreScale(float scale, float textWrapScale) { - DEBUG_NAV_UI_LOGD("%s", __FUNCTION__); - LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); + ALOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); JNIEnv* env = JSC::Bindings::getJNIEnv(); AutoJObject javaObject = m_javaGlue->object(env); @@ -1143,8 +1054,7 @@ void WebViewCore::restoreScale(float scale, float textWrapScale) void WebViewCore::needTouchEvents(bool need) { - DEBUG_NAV_UI_LOGD("%s", __FUNCTION__); - LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); + ALOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); #if ENABLE(TOUCH_EVENTS) JNIEnv* env = JSC::Bindings::getJNIEnv(); @@ -1162,26 +1072,9 @@ void WebViewCore::needTouchEvents(bool need) #endif } -void WebViewCore::requestKeyboardWithSelection(const WebCore::Node* node, - int selStart, int selEnd) -{ - DEBUG_NAV_UI_LOGD("%s", __FUNCTION__); - LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); - - JNIEnv* env = JSC::Bindings::getJNIEnv(); - AutoJObject javaObject = m_javaGlue->object(env); - if (!javaObject.get()) - return; - env->CallVoidMethod(javaObject.get(), - m_javaGlue->m_requestKeyboardWithSelection, - reinterpret_cast<int>(node), selStart, selEnd, m_textGeneration); - checkException(env); -} - void WebViewCore::requestKeyboard(bool showKeyboard) { - DEBUG_NAV_UI_LOGD("%s", __FUNCTION__); - LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); + ALOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); JNIEnv* env = JSC::Bindings::getJNIEnv(); AutoJObject javaObject = m_javaGlue->object(env); @@ -1193,42 +1086,15 @@ void WebViewCore::requestKeyboard(bool showKeyboard) void WebViewCore::notifyProgressFinished() { - m_check_domtree_version = true; sendNotifyProgressFinished(); } -void WebViewCore::doMaxScroll(CacheBuilder::Direction dir) -{ - int dx = 0, dy = 0; - - switch (dir) { - case CacheBuilder::LEFT: - dx = -m_maxXScroll; - break; - case CacheBuilder::UP: - dy = -m_maxYScroll; - break; - case CacheBuilder::RIGHT: - dx = m_maxXScroll; - break; - case CacheBuilder::DOWN: - dy = m_maxYScroll; - break; - case CacheBuilder::UNINITIALIZED: - default: - LOG_ASSERT(0, "unexpected focus selector"); - } - WebCore::FrameView* view = m_mainFrame->view(); - this->scrollTo(view->scrollX() + dx, view->scrollY() + dy, true); -} - -void WebViewCore::setScrollOffset(int moveGeneration, bool sendScrollEvent, int dx, int dy) +void WebViewCore::setScrollOffset(bool sendScrollEvent, int dx, int dy) { - DBG_NAV_LOGD("{%d,%d} m_scrollOffset=(%d,%d), sendScrollEvent=%d", dx, dy, - m_scrollOffsetX, m_scrollOffsetY, sendScrollEvent); if (m_scrollOffsetX != dx || m_scrollOffsetY != dy) { m_scrollOffsetX = dx; m_scrollOffsetY = dy; + m_scrollSetTime = currentTimeMS(); // The visible rect is located within our coordinate space so it // contains the actual scroll position. Setting the location makes hit // testing work correctly. @@ -1259,19 +1125,10 @@ void WebViewCore::setScrollOffset(int moveGeneration, bool sendScrollEvent, int // update the currently visible screen sendPluginVisibleScreen(); } - gCursorBoundsMutex.lock(); - bool hasCursorBounds = m_hasCursorBounds; - Frame* frame = (Frame*) m_cursorFrame; - IntPoint location = m_cursorLocation; - gCursorBoundsMutex.unlock(); - if (!hasCursorBounds) - return; - moveMouseIfLatest(moveGeneration, frame, location.x(), location.y()); } void WebViewCore::setGlobalBounds(int x, int y, int h, int v) { - DBG_NAV_LOGD("{%d,%d}", x, y); m_mainFrame->view()->platformWidget()->setWindowBounds(x, y, h, v); } @@ -1290,9 +1147,6 @@ void WebViewCore::setSizeScreenWidthAndScale(int width, int height, int osw = m_screenWidth; int osh = m_screenHeight; int otw = m_textWrapWidth; - float oldScale = m_scale; - DBG_NAV_LOGD("old:(w=%d,h=%d,sw=%d,scale=%g) new:(w=%d,h=%d,sw=%d,scale=%g)", - ow, oh, osw, m_scale, width, height, screenWidth, scale); m_screenWidth = screenWidth; m_screenHeight = screenHeight; m_textWrapWidth = textWrapWidth; @@ -1311,11 +1165,8 @@ void WebViewCore::setSizeScreenWidthAndScale(int width, int height, if (ow != width || (!ignoreHeight && oh != height) || reflow) { WebCore::RenderObject *r = m_mainFrame->contentRenderer(); - DBG_NAV_LOGD("renderer=%p view=(w=%d,h=%d)", r, - screenWidth, screenHeight); if (r) { WebCore::IntPoint anchorPoint = WebCore::IntPoint(anchorX, anchorY); - DBG_NAV_LOGD("anchorX=%d anchorY=%d", anchorX, anchorY); RefPtr<WebCore::Node> node; WebCore::IntRect bounds; WebCore::IntPoint offset; @@ -1327,11 +1178,19 @@ void WebViewCore::setSizeScreenWidthAndScale(int width, int height, m_mainFrame->eventHandler()->hitTestResultAtPoint( anchorPoint, false); node = hitTestResult.innerNode(); + if (node && !node->isTextNode()) { + // If the hitTestResultAtPoint didn't find a suitable node + // for anchoring, try again with some slop. + static const int HIT_SLOP = 30; + anchorPoint.move(HIT_SLOP, HIT_SLOP); + hitTestResult = + m_mainFrame->eventHandler()->hitTestResultAtPoint( + anchorPoint, false); + node = hitTestResult.innerNode(); + } } if (node) { bounds = node->getRect(); - DBG_NAV_LOGD("ob:(x=%d,y=%d,w=%d,h=%d)", - bounds.x(), bounds.y(), bounds.width(), bounds.height()); // sites like nytimes.com insert a non-standard tag <nyt_text> // in the html. If it is the HitTestResult, it may have zero // width and height. In this case, use its parent node. @@ -1339,8 +1198,6 @@ void WebViewCore::setSizeScreenWidthAndScale(int width, int height, node = node->parentOrHostNode(); if (node) { bounds = node->getRect(); - DBG_NAV_LOGD("found a zero width node and use its parent, whose ob:(x=%d,y=%d,w=%d,h=%d)", - bounds.x(), bounds.y(), bounds.width(), bounds.height()); } } } @@ -1361,9 +1218,6 @@ void WebViewCore::setSizeScreenWidthAndScale(int width, int height, // scroll to restore current screen center if (node && node->inDocument()) { const WebCore::IntRect& newBounds = node->getRect(); - DBG_NAV_LOGD("nb:(x=%d,y=%d,w=%d," - "h=%d)", newBounds.x(), newBounds.y(), - newBounds.width(), newBounds.height()); if ((osw && osh && bounds.width() && bounds.height()) && (bounds != newBounds)) { WebCore::FrameView* view = m_mainFrame->view(); @@ -1440,13 +1294,6 @@ void WebViewCore::dumpRenderTree(bool useFile) #endif } -void WebViewCore::dumpNavTree() -{ -#if DUMP_NAV_CACHE - cacheBuilder().mDebug.print(); -#endif -} - HTMLElement* WebViewCore::retrieveElement(int x, int y, const QualifiedName& tagName) { @@ -1455,12 +1302,12 @@ HTMLElement* WebViewCore::retrieveElement(int x, int y, DontHitTestScrollbars, HitTestRequest::Active | HitTestRequest::ReadOnly, IntSize(1, 1)); if (!hitTestResult.innerNode() || !hitTestResult.innerNode()->inDocument()) { - LOGE("Should not happen: no in document Node found"); + ALOGE("Should not happen: no in document Node found"); return 0; } const ListHashSet<RefPtr<Node> >& list = hitTestResult.rectBasedTestResult(); if (list.isEmpty()) { - LOGE("Should not happen: no rect-based-test nodes found"); + ALOGE("Should not happen: no rect-based-test nodes found"); return 0; } Node* node = hitTestResult.innerNode(); @@ -1469,9 +1316,6 @@ HTMLElement* WebViewCore::retrieveElement(int x, int y, || !element->hasTagName(tagName))) { element = element->parentNode(); } - DBG_NAV_LOGD("node=%p element=%p x=%d y=%d nodeName=%s tagName=%s", node, - element, x, y, node->nodeName().utf8().data(), - element ? ((Element*) element)->tagName().utf8().data() : "<none>"); return static_cast<WebCore::HTMLElement*>(element); } @@ -1489,8 +1333,10 @@ HTMLImageElement* WebViewCore::retrieveImageElement(int x, int y) WTF::String WebViewCore::retrieveHref(int x, int y) { - WebCore::HTMLAnchorElement* anchor = retrieveAnchorElement(x, y); - return anchor ? anchor->href() : WTF::String(); + // TODO: This is expensive, cache + HitTestResult result = m_mainFrame->eventHandler()->hitTestResultAtPoint(IntPoint(x, y), + false, false, DontHitTestScrollbars, HitTestRequest::Active | HitTestRequest::ReadOnly, IntSize(1, 1)); + return result.absoluteLinkURL(); } WTF::String WebViewCore::retrieveAnchorText(int x, int y) @@ -1501,14 +1347,16 @@ WTF::String WebViewCore::retrieveAnchorText(int x, int y) WTF::String WebViewCore::retrieveImageSource(int x, int y) { - HTMLImageElement* image = retrieveImageElement(x, y); - return image ? image->src().string() : WTF::String(); + // TODO: This is expensive, cache + HitTestResult result = m_mainFrame->eventHandler()->hitTestResultAtPoint(IntPoint(x, y), + false, false, DontHitTestScrollbars, HitTestRequest::Active | HitTestRequest::ReadOnly, IntSize(1, 1)); + return result.absoluteImageURL(); } WTF::String WebViewCore::requestLabel(WebCore::Frame* frame, WebCore::Node* node) { - if (node && CacheBuilder::validNode(m_mainFrame, frame, node)) { + if (node && validNode(m_mainFrame, frame, node)) { RefPtr<WebCore::NodeList> list = node->document()->getElementsByTagName("label"); unsigned length = list->length(); for (unsigned i = 0; i < length; i++) { @@ -1532,17 +1380,18 @@ WTF::String WebViewCore::requestLabel(WebCore::Frame* frame, static bool isContentEditable(const WebCore::Node* node) { - if (!node) return false; - return node->document()->frame()->selection()->isContentEditable(); + if (!node) + return false; + return node->isContentEditable(); } // Returns true if the node is a textfield, textarea, or contentEditable static bool isTextInput(const WebCore::Node* node) { - if (isContentEditable(node)) - return true; if (!node) return false; + if (isContentEditable(node)) + return true; WebCore::RenderObject* renderer = node->renderer(); return renderer && (renderer->isTextField() || renderer->isTextArea()); } @@ -1560,107 +1409,9 @@ void WebViewCore::revealSelection() focusedFrame->selection()->revealSelection(ScrollAlignment::alignToEdgeIfNeeded); } -void WebViewCore::updateCacheOnNodeChange() -{ - gCursorBoundsMutex.lock(); - bool hasCursorBounds = m_hasCursorBounds; - Frame* frame = (Frame*) m_cursorFrame; - Node* node = (Node*) m_cursorNode; - IntRect bounds = m_cursorHitBounds; - gCursorBoundsMutex.unlock(); - if (!hasCursorBounds || !node) - return; - if (CacheBuilder::validNode(m_mainFrame, frame, node)) { - RenderObject* renderer = node->renderer(); - if (renderer && renderer->style()->visibility() != HIDDEN) { - IntRect absBox = renderer->absoluteBoundingBoxRect(); - int globalX, globalY; - CacheBuilder::GetGlobalOffset(frame, &globalX, &globalY); - absBox.move(globalX, globalY); - if (absBox == bounds) - return; - DBG_NAV_LOGD("absBox=(%d,%d,%d,%d) bounds=(%d,%d,%d,%d)", - absBox.x(), absBox.y(), absBox.width(), absBox.height(), - bounds.x(), bounds.y(), bounds.width(), bounds.height()); - } - } - DBG_NAV_LOGD("updateFrameCache node=%p", node); - updateFrameCache(); -} - -void WebViewCore::updateFrameCache() -{ - if (!m_frameCacheOutOfDate) { - DBG_NAV_LOG("!m_frameCacheOutOfDate"); - return; - } - - // If there is a pending style recalculation, do not update the frame cache. - // Until the recalculation is complete, there may be internal objects that - // are in an inconsistent state (such as font pointers). - // In any event, there's not much point to updating the cache while a style - // recalculation is pending, since it will simply have to be updated again - // once the recalculation is complete. - // TODO: Do we need to reschedule an update for after the style is recalculated? - if (m_mainFrame && m_mainFrame->document() && m_mainFrame->document()->isPendingStyleRecalc()) { - LOGW("updateFrameCache: pending style recalc, ignoring."); - return; - } -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreBuildNavTimeCounter); -#endif - m_frameCacheOutOfDate = false; - m_temp = new CachedRoot(); - m_temp->init(m_mainFrame, &m_history); -#if USE(ACCELERATED_COMPOSITING) - GraphicsLayerAndroid* graphicsLayer = graphicsRootLayer(); - if (graphicsLayer) - m_temp->setRootLayer(graphicsLayer->contentLayer()); -#endif - CacheBuilder& builder = cacheBuilder(); - WebCore::Settings* settings = m_mainFrame->page()->settings(); - builder.allowAllTextDetection(); -#ifdef ANDROID_META_SUPPORT - if (settings) { - if (!settings->formatDetectionAddress()) - builder.disallowAddressDetection(); - if (!settings->formatDetectionEmail()) - builder.disallowEmailDetection(); - if (!settings->formatDetectionTelephone()) - builder.disallowPhoneDetection(); - } -#endif - builder.buildCache(m_temp); - m_tempPict = new SkPicture(); - recordPicture(m_tempPict); - m_temp->setPicture(m_tempPict); - m_temp->setTextGeneration(m_textGeneration); - WebCoreViewBridge* window = m_mainFrame->view()->platformWidget(); - m_temp->setVisibleRect(WebCore::IntRect(m_scrollOffsetX, - m_scrollOffsetY, window->width(), window->height())); - gFrameCacheMutex.lock(); - delete m_frameCacheKit; - delete m_navPictureKit; - m_frameCacheKit = m_temp; - m_navPictureKit = m_tempPict; - m_updatedFrameCache = true; -#if DEBUG_NAV_UI - const CachedNode* cachedFocusNode = m_frameCacheKit->currentFocus(); - DBG_NAV_LOGD("cachedFocusNode=%d (nodePointer=%p)", - cachedFocusNode ? cachedFocusNode->index() : 0, - cachedFocusNode ? cachedFocusNode->nodePointer() : 0); -#endif - gFrameCacheMutex.unlock(); -} - -void WebViewCore::updateFrameCacheIfLoading() -{ - if (!m_check_domtree_version) - updateFrameCache(); -} - struct TouchNodeData { - Node* mNode; + Node* mUrlNode; + Node* mInnerNode; IntRect mBounds; }; @@ -1668,6 +1419,8 @@ struct TouchNodeData { static IntRect getAbsoluteBoundingBox(Node* node) { IntRect rect; RenderObject* render = node->renderer(); + if (!render) + return rect; if (render->isRenderInline()) rect = toRenderInline(render)->linesVisualOverflowBoundingBox(); else if (render->isBox()) @@ -1675,30 +1428,395 @@ static IntRect getAbsoluteBoundingBox(Node* node) { else if (render->isText()) rect = toRenderText(render)->linesBoundingBox(); else - LOGE("getAbsoluteBoundingBox failed for node %p, name %s", node, render->renderName()); - FloatPoint absPos = render->localToAbsolute(); + ALOGE("getAbsoluteBoundingBox failed for node %p, name %s", node, render->renderName()); + FloatPoint absPos = render->localToAbsolute(FloatPoint(), false, true); rect.move(absPos.x(), absPos.y()); return rect; } +WebCore::Frame* WebViewCore::focusedFrame() const +{ + return m_mainFrame->page()->focusController()->focusedOrMainFrame(); +} + +VisiblePosition WebViewCore::visiblePositionForContentPoint(int x, int y) +{ + return visiblePositionForContentPoint(IntPoint(x, y)); +} + +VisiblePosition WebViewCore::visiblePositionForContentPoint(const IntPoint& point) +{ + // Hit test of this kind required for this to work inside input fields + HitTestRequest request(HitTestRequest::Active + | HitTestRequest::MouseMove + | HitTestRequest::ReadOnly + | HitTestRequest::IgnoreClipping); + HitTestResult result(point); + focusedFrame()->document()->renderView()->layer()->hitTest(request, result); + + // Matching the logic in MouseEventWithHitTestResults::targetNode() + Node* node = result.innerNode(); + if (!node) + return VisiblePosition(); + Element* element = node->parentElement(); + if (!node->inDocument() && element && element->inDocument()) + node = element; + + return node->renderer()->positionForPoint(result.localPoint()); +} + +bool WebViewCore::selectWordAt(int x, int y) +{ + HitTestResult hoverResult; + moveMouse(x, y, &hoverResult); + if (hoverResult.innerNode()) { + Node* node = hoverResult.innerNode(); + Frame* frame = node->document()->frame(); + Page* page = m_mainFrame->document()->page(); + page->focusController()->setFocusedFrame(frame); + } + + IntPoint point = convertGlobalContentToFrameContent(IntPoint(x, y)); + + // Hit test of this kind required for this to work inside input fields + HitTestRequest request(HitTestRequest::Active); + HitTestResult result(point); + + focusedFrame()->document()->renderView()->layer()->hitTest(request, result); + + // Matching the logic in MouseEventWithHitTestResults::targetNode() + Node* node = result.innerNode(); + if (!node) + return false; + Element* element = node->parentElement(); + if (!node->inDocument() && element && element->inDocument()) + node = element; + + SelectionController* sc = focusedFrame()->selection(); + bool wordSelected = false; + if (!sc->contains(point) && (node->isContentEditable() || node->isTextNode()) && !result.isLiveLink() + && node->dispatchEvent(Event::create(eventNames().selectstartEvent, true, true))) { + VisiblePosition pos(node->renderer()->positionForPoint(result.localPoint())); + wordSelected = selectWordAroundPosition(node->document()->frame(), pos); + } + return wordSelected; +} + +bool WebViewCore::selectWordAroundPosition(Frame* frame, VisiblePosition pos) +{ + VisibleSelection selection(pos); + selection.expandUsingGranularity(WordGranularity); + SelectionController* selectionController = frame->selection(); + + bool wordSelected = false; + if (selectionController->shouldChangeSelection(selection)) { + bool allWhitespaces = true; + RefPtr<Range> firstRange = selection.firstRange(); + String text = firstRange.get() ? firstRange->text() : ""; + for (size_t i = 0; i < text.length(); ++i) { + if (!isSpaceOrNewline(text[i])) { + allWhitespaces = false; + break; + } + } + if (allWhitespaces) { + VisibleSelection emptySelection(pos); + selectionController->setSelection(emptySelection); + } else { + selectionController->setSelection(selection); + wordSelected = true; + } + } + return wordSelected; +} + +int WebViewCore::platformLayerIdFromNode(Node* node, LayerAndroid** outLayer) +{ + if (!node || !node->renderer()) + return -1; + RenderLayer* renderLayer = node->renderer()->enclosingLayer(); + while (renderLayer && !renderLayer->isComposited()) + renderLayer = renderLayer->parent(); + if (!renderLayer || !renderLayer->isComposited()) + return -1; + GraphicsLayer* graphicsLayer = renderLayer->backing()->graphicsLayer(); + if (!graphicsLayer) + return -1; + GraphicsLayerAndroid* agl = static_cast<GraphicsLayerAndroid*>(graphicsLayer); + LayerAndroid* layer = agl->foregroundLayer(); + if (!layer) + layer = agl->contentLayer(); + if (!layer) + return -1; + if (outLayer) + *outLayer = layer; + return layer->uniqueId(); +} + +void WebViewCore::layerToAbsoluteOffset(const LayerAndroid* layer, IntPoint& offset) +{ + while (layer) { + const SkPoint& pos = layer->getPosition(); + offset.move(pos.fX, pos.fY); + const IntPoint& scroll = layer->getScrollOffset(); + offset.move(-scroll.x(), -scroll.y()); + layer = static_cast<LayerAndroid*>(layer->getParent()); + } +} + +void WebViewCore::setSelectionCaretInfo(SelectText* selectTextContainer, + const WebCore::Position& pos, const IntPoint& frameOffset, + SelectText::HandleId handleId, int caretRectOffset, EAffinity affinity) +{ + Node* node = pos.anchorNode(); + LayerAndroid* layer = 0; + int layerId = platformLayerIdFromNode(node, &layer); + selectTextContainer->setCaretLayerId(handleId, layerId); + IntPoint offset = frameOffset; + layerToAbsoluteOffset(layer, offset); + RenderObject* r = node->renderer(); + RenderText* renderText = toRenderText(r); + int caretOffset; + InlineBox* inlineBox; + pos.getInlineBoxAndOffset(affinity, inlineBox, caretOffset); + IntRect caretRect = renderText->localCaretRect(inlineBox, caretOffset); + FloatPoint absoluteOffset = renderText->localToAbsolute(caretRect.location()); + caretRect.setX(absoluteOffset.x() - offset.x() + caretRectOffset); + caretRect.setY(absoluteOffset.y() - offset.y()); + selectTextContainer->setCaretRect(handleId, caretRect); + selectTextContainer->setTextRect(handleId, + positionToTextRect(pos, affinity, offset)); +} + +bool WebViewCore::isLtr(const Position& position) +{ + InlineBox* inlineBox = 0; + int caretOffset = 0; + position.getInlineBoxAndOffset(DOWNSTREAM, inlineBox, caretOffset); + bool isLtr; + if (inlineBox) + isLtr = inlineBox->isLeftToRightDirection(); + else + isLtr = position.primaryDirection() == LTR; + return isLtr; +} + +SelectText* WebViewCore::createSelectText(const VisibleSelection& selection) +{ + bool isCaret = selection.isCaret(); + if (selection.isNone() || (!selection.isContentEditable() && isCaret) + || !selection.start().anchorNode() + || !selection.start().anchorNode()->renderer() + || !selection.end().anchorNode() + || !selection.end().anchorNode()->renderer()) + return 0; + + RefPtr<Range> range = selection.firstRange(); + Node* startContainer = range->startContainer(); + Node* endContainer = range->endContainer(); + + if (!startContainer || !endContainer) + return 0; + if (!isCaret && startContainer == endContainer + && range->startOffset() == range->endOffset()) + return 0; + + IntPoint frameOffset = convertGlobalContentToFrameContent(IntPoint()); + SelectText* selectTextContainer = new SelectText(); + if (isCaret) { + setSelectionCaretInfo(selectTextContainer, selection.start(), frameOffset, + SelectText::LeftHandle, 0, selection.affinity()); + setSelectionCaretInfo(selectTextContainer, selection.start(), frameOffset, + SelectText::RightHandle, 0, selection.affinity()); + } else { + bool ltr = isLtr(selection.start()); + Position left = ltr ? selection.start() : selection.end(); + Position right = ltr ? selection.end() : selection.start(); + int leftOffset = isLtr(left) ? 0 : -1; + int rightOffset = isLtr(right) ? 0 : -1; + setSelectionCaretInfo(selectTextContainer, left, frameOffset, + SelectText::LeftHandle, leftOffset, selection.affinity()); + setSelectionCaretInfo(selectTextContainer, right, frameOffset, + SelectText::RightHandle, rightOffset, selection.affinity()); + + Node* stopNode = range->pastLastNode(); + for (Node* node = range->firstNode(); node != stopNode; node = node->traverseNextNode()) { + RenderObject* r = node->renderer(); + if (!r || !r->isText() || r->style()->visibility() != VISIBLE) + continue; + RenderText* renderText = toRenderText(r); + int startOffset = node == startContainer ? range->startOffset() : 0; + int endOffset = node == endContainer ? range->endOffset() : numeric_limits<int>::max(); + LayerAndroid* layer = 0; + int layerId = platformLayerIdFromNode(node, &layer); + Vector<IntRect> rects; + renderText->absoluteRectsForRange(rects, startOffset, endOffset, true); + selectTextContainer->addHighlightRegion(layer, rects, frameOffset); + } + } + selectTextContainer->setText(range->text()); + return selectTextContainer; +} + +IntRect WebViewCore::positionToTextRect(const Position& position, + EAffinity affinity, const WebCore::IntPoint& offset) +{ + IntRect textRect; + InlineBox* inlineBox; + int offsetIndex; + position.getInlineBoxAndOffset(affinity, inlineBox, offsetIndex); + if (inlineBox && inlineBox->isInlineTextBox()) { + InlineTextBox* box = static_cast<InlineTextBox*>(inlineBox); + RootInlineBox* root = box->root(); + RenderText* renderText = box->textRenderer(); + int left = root->logicalLeft(); + int width = root->logicalWidth(); + int top = root->selectionTop(); + int height = root->selectionHeight(); + + if (!renderText->style()->isHorizontalWritingMode()) { + swap(left, top); + swap(width, height); + } + FloatPoint origin(left, top); + FloatPoint absoluteOrigin = renderText->localToAbsolute(origin); + + textRect.setX(absoluteOrigin.x() - offset.x()); + textRect.setWidth(width); + textRect.setY(absoluteOrigin.y() - offset.y()); + textRect.setHeight(height); + } + return textRect; +} + +IntPoint WebViewCore::convertGlobalContentToFrameContent(const IntPoint& point, WebCore::Frame* frame) +{ + if (!frame) frame = focusedFrame(); + IntPoint frameOffset(-m_scrollOffsetX, -m_scrollOffsetY); + frameOffset = frame->view()->windowToContents(frameOffset); + return IntPoint(point.x() + frameOffset.x(), point.y() + frameOffset.y()); +} + +Position WebViewCore::trimSelectionPosition(const Position &start, const Position& stop) +{ + int direction = comparePositions(start, stop); + if (direction == 0) + return start; + bool forward = direction < 0; + EAffinity affinity = forward ? DOWNSTREAM : UPSTREAM; + bool move; + Position pos = start; + bool movedTooFar = false; + do { + move = true; + Node* node = pos.anchorNode(); + if (node && node->isTextNode() && node->renderer()) { + RenderText *textRenderer = toRenderText(node->renderer()); + move = !textRenderer->textLength(); + } + if (move) { + Position nextPos = forward ? pos.next() : pos.previous(); + movedTooFar = nextPos.isNull() || pos == nextPos + || ((comparePositions(nextPos, stop) < 0) != forward); + pos = nextPos; + } + } while (move && !movedTooFar); + if (movedTooFar) + pos = stop; + return pos; +} + +void WebViewCore::selectText(int startX, int startY, int endX, int endY) +{ + SelectionController* sc = focusedFrame()->selection(); + IntPoint startPoint = convertGlobalContentToFrameContent(IntPoint(startX, startY)); + VisiblePosition startPosition(visiblePositionForContentPoint(startPoint)); + IntPoint endPoint = convertGlobalContentToFrameContent(IntPoint(endX, endY)); + VisiblePosition endPosition(visiblePositionForContentPoint(endPoint)); + + if (startPosition.isNull() || endPosition.isNull()) + return; + + // Ensure startPosition is before endPosition + if (comparePositions(startPosition, endPosition) > 0) + swap(startPosition, endPosition); + + if (sc->isContentEditable()) { + startPosition = sc->selection().visibleStart().honorEditableBoundaryAtOrAfter(startPosition); + endPosition = sc->selection().visibleEnd().honorEditableBoundaryAtOrBefore(endPosition); + if (startPosition.isNull() || endPosition.isNull()) { + return; + } + } + + // Ensure startPosition is not at end of block + if (startPosition != endPosition && isEndOfBlock(startPosition)) { + VisiblePosition nextStartPosition(startPosition.next()); + if (!nextStartPosition.isNull()) + startPosition = nextStartPosition; + } + // Ensure endPosition is not at start of block + if (startPosition != endPosition && isStartOfBlock(endPosition)) { + VisiblePosition prevEndPosition(endPosition.previous()); + if (!prevEndPosition.isNull()) + endPosition = prevEndPosition; + } + + Position start = startPosition.deepEquivalent(); + Position end = endPosition.deepEquivalent(); + start = trimSelectionPosition(start, end); + end = trimSelectionPosition(end, start); + VisibleSelection selection(start, end); + // Only allow changes between caret positions or to text selection. + bool selectChangeAllowed = (!selection.isCaret() || sc->isCaret()); + if (selectChangeAllowed && sc->shouldChangeSelection(selection)) + sc->setSelection(selection); +} + +bool WebViewCore::nodeIsClickableOrFocusable(Node* node) +{ + if (!node) + return false; + if (node->disabled()) + return false; + if (!node->inDocument()) + return false; + if (!node->renderer() || node->renderer()->style()->visibility() != VISIBLE) + return false; + return node->supportsFocus() + || node->hasEventListeners(eventNames().clickEvent) + || node->hasEventListeners(eventNames().mousedownEvent) + || node->hasEventListeners(eventNames().mouseupEvent) + || node->hasEventListeners(eventNames().mouseoverEvent); +} + // get the highlight rectangles for the touch point (x, y) with the slop -Vector<IntRect> WebViewCore::getTouchHighlightRects(int x, int y, int slop) +AndroidHitTestResult WebViewCore::hitTestAtPoint(int x, int y, int slop, bool doMoveMouse) { - Vector<IntRect> rects; - m_mousePos = IntPoint(x - m_scrollOffsetX, y - m_scrollOffsetY); + if (doMoveMouse) + moveMouse(x, y, 0, true); HitTestResult hitTestResult = m_mainFrame->eventHandler()->hitTestResultAtPoint(IntPoint(x, y), false, false, DontHitTestScrollbars, HitTestRequest::Active | HitTestRequest::ReadOnly, IntSize(slop, slop)); + AndroidHitTestResult androidHitResult(this, hitTestResult); if (!hitTestResult.innerNode() || !hitTestResult.innerNode()->inDocument()) { - LOGE("Should not happen: no in document Node found"); - return rects; + ALOGE("Should not happen: no in document Node found"); + return androidHitResult; } const ListHashSet<RefPtr<Node> >& list = hitTestResult.rectBasedTestResult(); if (list.isEmpty()) { - LOGE("Should not happen: no rect-based-test nodes found"); - return rects; + ALOGE("Should not happen: no rect-based-test nodes found"); + return androidHitResult; } Frame* frame = hitTestResult.innerNode()->document()->frame(); Vector<TouchNodeData> nodeDataList; + if (hitTestResult.innerNode() != hitTestResult.innerNonSharedNode() + && hitTestResult.innerNode()->hasTagName(WebCore::HTMLNames::areaTag)) { + HTMLAreaElement* area = static_cast<HTMLAreaElement*>(hitTestResult.innerNode()); + androidHitResult.hitTestResult().setURLElement(area); + androidHitResult.highlightRects().append(area->computeRect( + hitTestResult.innerNonSharedNode()->renderer())); + return androidHitResult; + } ListHashSet<RefPtr<Node> >::const_iterator last = list.end(); for (ListHashSet<RefPtr<Node> >::const_iterator it = list.begin(); it != last; ++it) { // TODO: it seems reasonable to not search across the frame. Isn't it? @@ -1708,14 +1826,12 @@ Vector<IntRect> WebViewCore::getTouchHighlightRects(int x, int y, int slop) // traverse up the tree to find the first node that needs highlight bool found = false; Node* eventNode = it->get(); + Node* innerNode = eventNode; while (eventNode) { RenderObject* render = eventNode->renderer(); if (render && (render->isBody() || render->isRenderView())) break; - if (eventNode->supportsFocus() - || eventNode->hasEventListeners(eventNames().clickEvent) - || eventNode->hasEventListeners(eventNames().mousedownEvent) - || eventNode->hasEventListeners(eventNames().mouseupEvent)) { + if (nodeIsClickableOrFocusable(eventNode)) { found = true; break; } @@ -1747,7 +1863,7 @@ Vector<IntRect> WebViewCore::getTouchHighlightRects(int x, int y, int slop) Vector<TouchNodeData>::const_iterator nlast = nodeDataList.end(); for (Vector<TouchNodeData>::const_iterator n = nodeDataList.begin(); n != nlast; ++n) { // found the same node, skip it - if (eventNode == n->mNode) { + if (eventNode == n->mUrlNode) { found = false; break; } @@ -1788,16 +1904,19 @@ Vector<IntRect> WebViewCore::getTouchHighlightRects(int x, int y, int slop) } if (!found) { TouchNodeData newNode; - newNode.mNode = eventNode; + newNode.mUrlNode = eventNode; newNode.mBounds = rect; + newNode.mInnerNode = innerNode; nodeDataList.append(newNode); } } - if (!nodeDataList.size()) - return rects; + if (!nodeDataList.size()) { + androidHitResult.searchContentDetectors(); + return androidHitResult; + } // finally select the node with the largest overlap with the fat point TouchNodeData final; - final.mNode = 0; + final.mUrlNode = 0; IntPoint docPos = frame->view()->windowToContents(m_mousePos); IntRect testRect(docPos.x() - slop, docPos.y() - slop, 2 * slop + 1, 2 * slop + 1); int area = 0; @@ -1806,101 +1925,47 @@ Vector<IntRect> WebViewCore::getTouchHighlightRects(int x, int y, int slop) IntRect rect = n->mBounds; rect.intersect(testRect); int a = rect.width() * rect.height(); - if (a > area) { + if (a > area || !final.mUrlNode) { final = *n; area = a; } } // now get the node's highlight rectangles in the page coordinate system - if (final.mNode) { - IntPoint frameAdjust; - if (frame != m_mainFrame) { - frameAdjust = frame->view()->contentsToWindow(IntPoint()); - frameAdjust.move(m_scrollOffsetX, m_scrollOffsetY); + if (final.mUrlNode) { + // Update innerNode and innerNonSharedNode + androidHitResult.hitTestResult().setInnerNode(final.mInnerNode); + androidHitResult.hitTestResult().setInnerNonSharedNode(final.mInnerNode); + if (final.mUrlNode->isElementNode()) { + // We found a URL element. Update the hitTestResult + androidHitResult.setURLElement(static_cast<Element*>(final.mUrlNode)); + } else { + androidHitResult.setURLElement(0); } - if (final.mNode->isLink()) { - // most of the links are inline instead of box style. So the bounding box is not - // a good representation for the highlights. Get the list of rectangles instead. - RenderObject* render = final.mNode->renderer(); - IntPoint offset = roundedIntPoint(render->localToAbsolute()); - render->absoluteRects(rects, offset.x() + frameAdjust.x(), offset.y() + frameAdjust.y()); - bool inside = false; - int distance = INT_MAX; - int newx = x, newy = y; - int i = rects.size(); - while (i--) { - if (rects[i].isEmpty()) { - rects.remove(i); - continue; - } - // check whether the point (x, y) is inside one of the rectangles. - if (inside) - continue; - if (rects[i].contains(x, y)) { - inside = true; - continue; - } - if (x >= rects[i].x() && x < rects[i].maxX()) { - if (y < rects[i].y()) { - if (rects[i].y() - y < distance) { - newx = x; - newy = rects[i].y(); - distance = rects[i].y() - y; - } - } else if (y >= rects[i].maxY()) { - if (y - rects[i].maxY() + 1 < distance) { - newx = x; - newy = rects[i].maxY() - 1; - distance = y - rects[i].maxY() + 1; - } - } - } else if (y >= rects[i].y() && y < rects[i].maxY()) { - if (x < rects[i].x()) { - if (rects[i].x() - x < distance) { - newx = rects[i].x(); - newy = y; - distance = rects[i].x() - x; - } - } else if (x >= rects[i].maxX()) { - if (x - rects[i].maxX() + 1 < distance) { - newx = rects[i].maxX() - 1; - newy = y; - distance = x - rects[i].maxX() + 1; - } - } + Vector<IntRect>& highlightRects = androidHitResult.highlightRects(); + if (doMoveMouse && highlightRects.size() > 0) { + // adjust m_mousePos if it is not inside the returned highlight + // rectangles + IntRect foundIntersection; + IntRect inputRect = IntRect(x - slop, y - slop, + slop * 2 + 1, slop * 2 + 1); + for (size_t i = 0; i < highlightRects.size(); i++) { + IntRect& hr = highlightRects[i]; + IntRect test = inputRect; + test.intersect(hr); + if (!test.isEmpty()) { + foundIntersection = test; + break; } } - if (!rects.isEmpty()) { - if (!inside) { - // if neither x nor y has overlap, just pick the top/left of the first rectangle - if (newx == x && newy == y) { - newx = rects[0].x(); - newy = rects[0].y(); - } - m_mousePos.setX(newx - m_scrollOffsetX); - m_mousePos.setY(newy - m_scrollOffsetY); - DBG_NAV_LOGD("Move x/y from (%d, %d) to (%d, %d) scrollOffset is (%d, %d)", - x, y, m_mousePos.x() + m_scrollOffsetX, m_mousePos.y() + m_scrollOffsetY, - m_scrollOffsetX, m_scrollOffsetY); - } - return rects; + if (!foundIntersection.isEmpty() && !foundIntersection.contains(x, y)) { + IntPoint pt = foundIntersection.center(); + moveMouse(pt.x(), pt.y(), 0, true); } } - IntRect rect = final.mBounds; - rect.move(frameAdjust.x(), frameAdjust.y()); - rects.append(rect); - // adjust m_mousePos if it is not inside the returned highlight rectangle - testRect.move(frameAdjust.x(), frameAdjust.y()); - testRect.intersect(rect); - if (!testRect.contains(x, y)) { - m_mousePos = testRect.center(); - m_mousePos.move(-m_scrollOffsetX, -m_scrollOffsetY); - DBG_NAV_LOGD("Move x/y from (%d, %d) to (%d, %d) scrollOffset is (%d, %d)", - x, y, m_mousePos.x() + m_scrollOffsetX, m_mousePos.y() + m_scrollOffsetY, - m_scrollOffsetX, m_scrollOffsetY); - } + } else { + androidHitResult.searchContentDetectors(); } - return rects; + return androidHitResult; } /////////////////////////////////////////////////////////////////////////////// @@ -2071,70 +2136,46 @@ static PluginView* nodeIsPlugin(Node* node) { return 0; } -Node* WebViewCore::cursorNodeIsPlugin() { - gCursorBoundsMutex.lock(); - bool hasCursorBounds = m_hasCursorBounds; - Frame* frame = (Frame*) m_cursorFrame; - Node* node = (Node*) m_cursorNode; - gCursorBoundsMutex.unlock(); - if (hasCursorBounds && CacheBuilder::validNode(m_mainFrame, frame, node) - && nodeIsPlugin(node)) { - return node; - } - return 0; -} - /////////////////////////////////////////////////////////////////////////////// -void WebViewCore::moveMouseIfLatest(int moveGeneration, - WebCore::Frame* frame, int x, int y) -{ - DBG_NAV_LOGD("m_moveGeneration=%d moveGeneration=%d" - " frame=%p x=%d y=%d", - m_moveGeneration, moveGeneration, frame, x, y); - if (m_moveGeneration > moveGeneration) { - DBG_NAV_LOGD("m_moveGeneration=%d > moveGeneration=%d", - m_moveGeneration, moveGeneration); - return; // short-circuit if a newer move has already been generated - } - m_lastGeneration = moveGeneration; - moveMouse(frame, x, y); -} - -void WebViewCore::moveFocus(WebCore::Frame* frame, WebCore::Node* node) -{ - DBG_NAV_LOGD("frame=%p node=%p", frame, node); - if (!node || !CacheBuilder::validNode(m_mainFrame, frame, node) - || !node->isElementNode()) - return; - // Code borrowed from FocusController::advanceFocus - WebCore::FocusController* focusController - = m_mainFrame->page()->focusController(); - WebCore::Document* oldDoc - = focusController->focusedOrMainFrame()->document(); - if (oldDoc->focusedNode() == node) - return; - if (node->document() != oldDoc) - oldDoc->setFocusedNode(0); - focusController->setFocusedFrame(frame); - static_cast<WebCore::Element*>(node)->focus(false); -} // Update mouse position -void WebViewCore::moveMouse(WebCore::Frame* frame, int x, int y) +void WebViewCore::moveMouse(int x, int y, HitTestResult* hoveredNode, bool isClickCandidate) { - DBG_NAV_LOGD("frame=%p x=%d y=%d scrollOffset=(%d,%d)", frame, - x, y, m_scrollOffsetX, m_scrollOffsetY); - if (!frame || !CacheBuilder::validNode(m_mainFrame, frame, 0)) - frame = m_mainFrame; // mouse event expects the position in the window coordinate m_mousePos = WebCore::IntPoint(x - m_scrollOffsetX, y - m_scrollOffsetY); + if (isClickCandidate) + m_mouseClickPos = m_mousePos; // validNode will still return true if the node is null, as long as we have // a valid frame. Do not want to make a call on frame unless it is valid. WebCore::PlatformMouseEvent mouseEvent(m_mousePos, m_mousePos, WebCore::NoButton, WebCore::MouseEventMoved, 1, false, false, false, false, WTF::currentTime()); - frame->eventHandler()->handleMouseMoveEvent(mouseEvent); - updateCacheOnNodeChange(); + m_mainFrame->eventHandler()->handleMouseMoveEvent(mouseEvent, hoveredNode); +} + +Position WebViewCore::getPositionForOffset(Node* node, int offset) +{ + Position start = firstPositionInNode(node); + Position end = lastPositionInNode(node); + Document* document = node->document(); + PassRefPtr<Range> range = Range::create(document, start, end); + WebCore::CharacterIterator iterator(range.get()); + iterator.advance(offset); + return iterator.range()->startPosition(); +} + +void WebViewCore::setSelection(Node* node, int start, int end) +{ + RenderTextControl* control = toRenderTextControl(node); + if (control) + setSelectionRange(node, start, end); + else { + Position startPosition = getPositionForOffset(node, start); + Position endPosition = getPositionForOffset(node, end); + VisibleSelection selection(startPosition, endPosition); + SelectionController* selector = node->document()->frame()->selection(); + selector->setSelection(selection); + } } void WebViewCore::setSelection(int start, int end) @@ -2142,28 +2183,22 @@ void WebViewCore::setSelection(int start, int end) WebCore::Node* focus = currentFocus(); if (!focus) return; - WebCore::RenderObject* renderer = focus->renderer(); - if (!renderer || (!renderer->isTextField() && !renderer->isTextArea())) - return; - if (start > end) { - int temp = start; - start = end; - end = temp; - } + if (start > end) + swap(start, end); + // Tell our EditorClient that this change was generated from the UI, so it // does not need to echo it to the UI. EditorClientAndroid* client = static_cast<EditorClientAndroid*>( m_mainFrame->editor()->client()); client->setUiGeneratedSelectionChange(true); - setSelectionRange(focus, start, end); - if (start != end) { + setSelection(focus, start, end); + RenderTextControl* control = toRenderTextControl(focus); + if (start != end && control) { // Fire a select event. No event is sent when the selection reduces to // an insertion point - RenderTextControl* control = toRenderTextControl(renderer); control->selectionChanged(true); } client->setUiGeneratedSelectionChange(false); - WebCore::Frame* focusedFrame = focus->document()->frame(); bool isPasswordField = false; if (focus->isElementNode()) { WebCore::Element* element = static_cast<WebCore::Element*>(focus); @@ -2172,7 +2207,7 @@ void WebViewCore::setSelection(int start, int end) } // For password fields, this is done in the UI side via // bringPointIntoView, since the UI does the drawing. - if (renderer->isTextArea() || !isPasswordField) + if ((control && control->isTextArea()) || !isPasswordField) revealSelection(); } @@ -2197,7 +2232,7 @@ String WebViewCore::modifySelection(const int direction, const int axis) case AXIS_DOCUMENT: return modifySelectionDomNavigationAxis(selection, direction, axis); default: - LOGE("Invalid navigation axis: %d", axis); + ALOGE("Invalid navigation axis: %d", axis); return String(); } } @@ -2238,9 +2273,9 @@ String WebViewCore::modifySelectionTextNavigationAxis(DOMSelection* selection, i // initialize the selection if necessary if (selection->rangeCount() == 0) { if (m_currentNodeDomNavigationAxis - && CacheBuilder::validNode(m_mainFrame, + && validNode(m_mainFrame, m_mainFrame, m_currentNodeDomNavigationAxis)) { - PassRefPtr<Range> rangeRef = + RefPtr<Range> rangeRef = selection->frame()->document()->createRange(); rangeRef->selectNode(m_currentNodeDomNavigationAxis, ec); m_currentNodeDomNavigationAxis = 0; @@ -2249,15 +2284,6 @@ String WebViewCore::modifySelectionTextNavigationAxis(DOMSelection* selection, i selection->addRange(rangeRef.get()); } else if (currentFocus()) { selection->setPosition(currentFocus(), 0, ec); - } else if (m_cursorNode - && CacheBuilder::validNode(m_mainFrame, - m_mainFrame, m_cursorNode)) { - PassRefPtr<Range> rangeRef = - selection->frame()->document()->createRange(); - rangeRef->selectNode(reinterpret_cast<Node*>(m_cursorNode), ec); - if (ec) - return String(); - selection->addRange(rangeRef.get()); } else { selection->setPosition(body, 0, ec); } @@ -2456,13 +2482,13 @@ String WebViewCore::modifySelectionTextNavigationAxis(DOMSelection* selection, i scrollNodeIntoView(m_mainFrame, selection->anchorNode()); // format markup for the visible content - PassRefPtr<Range> range = selection->getRangeAt(0, ec); + RefPtr<Range> range = selection->getRangeAt(0, ec); if (ec) return String(); IntRect bounds = range->boundingBox(); selectAt(bounds.center().x(), bounds.center().y()); markup = formatMarkup(selection); - LOGV("Selection markup: %s", markup.utf8().data()); + ALOGV("Selection markup: %s", markup.utf8().data()); return markup; } @@ -2670,7 +2696,7 @@ String WebViewCore::modifySelectionDomNavigationAxis(DOMSelection* selection, in if (!m_currentNodeDomNavigationAxis) m_currentNodeDomNavigationAxis = currentFocus(); if (!m_currentNodeDomNavigationAxis - || !CacheBuilder::validNode(m_mainFrame, m_mainFrame, + || !validNode(m_mainFrame, m_mainFrame, m_currentNodeDomNavigationAxis)) m_currentNodeDomNavigationAxis = body; Node* currentNode = m_currentNodeDomNavigationAxis; @@ -2714,14 +2740,14 @@ String WebViewCore::modifySelectionDomNavigationAxis(DOMSelection* selection, in if (direction == DIRECTION_FORWARD) currentNode = currentNode->lastDescendant(); } else { - LOGE("Invalid axis: %d", axis); + ALOGE("Invalid axis: %d", axis); return String(); } if (currentNode) { m_currentNodeDomNavigationAxis = currentNode; scrollNodeIntoView(m_mainFrame, currentNode); String selectionString = createMarkup(currentNode); - LOGV("Selection markup: %s", selectionString.utf8().data()); + ALOGV("Selection markup: %s", selectionString.utf8().data()); return selectionString; } return String(); @@ -2771,7 +2797,7 @@ bool WebViewCore::isVisible(Node* node) while (currentNode && currentNode != body) { RenderStyle* style = currentNode->computedStyle(); if (style && - (style->display() == NONE || style->visibility() == HIDDEN)) { + (style->display() == WebCore::NONE || style->visibility() == WebCore::HIDDEN)) { return false; } currentNode = currentNode->parentNode(); @@ -2783,7 +2809,7 @@ String WebViewCore::formatMarkup(DOMSelection* selection) { ExceptionCode ec = 0; String markup = String(); - PassRefPtr<Range> wholeRange = selection->getRangeAt(0, ec); + RefPtr<Range> wholeRange = selection->getRangeAt(0, ec); if (ec) return String(); if (!wholeRange->startContainer() || !wholeRange->startContainer()) @@ -2793,7 +2819,7 @@ String WebViewCore::formatMarkup(DOMSelection* selection) Node* firstNode = wholeRange->firstNode(); Node* pastLastNode = wholeRange->pastLastNode(); Node* currentNode = firstNode; - PassRefPtr<Range> currentRange; + RefPtr<Range> currentRange; while (currentNode != pastLastNode) { Node* nextNode = currentNode->traverseNextNode(); @@ -2870,7 +2896,6 @@ void WebViewCore::deleteSelection(int start, int end, int textGeneration) key(up); client->setUiGeneratedSelectionChange(false); m_textGeneration = textGeneration; - m_shouldPaintCaret = true; } void WebViewCore::replaceTextfieldText(int oldStart, @@ -2886,13 +2911,15 @@ void WebViewCore::replaceTextfieldText(int oldStart, EditorClientAndroid* client = static_cast<EditorClientAndroid*>( m_mainFrame->editor()->client()); client->setUiGeneratedSelectionChange(true); - WebCore::TypingCommand::insertText(focus->document(), replace, - false); + if (replace.length()) + WebCore::TypingCommand::insertText(focus->document(), replace, + false); + else + WebCore::TypingCommand::deleteSelection(focus->document()); client->setUiGeneratedSelectionChange(false); // setSelection calls revealSelection, so there is no need to do it here. setSelection(start, end); m_textGeneration = textGeneration; - m_shouldPaintCaret = true; } void WebViewCore::passToJs(int generation, const WTF::String& current, @@ -2900,13 +2927,6 @@ void WebViewCore::passToJs(int generation, const WTF::String& current, { WebCore::Node* focus = currentFocus(); if (!focus) { - DBG_NAV_LOG("!focus"); - clearTextEntry(); - return; - } - WebCore::RenderObject* renderer = focus->renderer(); - if (!renderer || (!renderer->isTextField() && !renderer->isTextArea())) { - DBG_NAV_LOGD("renderer==%p || not text", renderer); clearTextEntry(); return; } @@ -2921,42 +2941,36 @@ void WebViewCore::passToJs(int generation, const WTF::String& current, client->setUiGeneratedSelectionChange(false); m_blockTextfieldUpdates = false; m_textGeneration = generation; - WebCore::RenderTextControl* renderText = - static_cast<WebCore::RenderTextControl*>(renderer); - WTF::String test = renderText->text(); + WTF::String test = getInputText(focus); if (test != current) { // If the text changed during the key event, update the UI text field. updateTextfield(focus, false, test); - } else { - DBG_NAV_LOG("test == current"); } // Now that the selection has settled down, send it. updateTextSelection(); - m_shouldPaintCaret = true; } -void WebViewCore::scrollFocusedTextInput(float xPercent, int y) +WebCore::IntRect WebViewCore::scrollFocusedTextInput(float xPercent, int y) { WebCore::Node* focus = currentFocus(); if (!focus) { - DBG_NAV_LOG("!focus"); clearTextEntry(); - return; + return WebCore::IntRect(); } - WebCore::RenderObject* renderer = focus->renderer(); - if (!renderer || (!renderer->isTextField() && !renderer->isTextArea())) { - DBG_NAV_LOGD("renderer==%p || not text", renderer); + WebCore::RenderTextControl* renderText = toRenderTextControl(focus); + if (!renderText) { clearTextEntry(); - return; + return WebCore::IntRect(); } - WebCore::RenderTextControl* renderText = - static_cast<WebCore::RenderTextControl*>(renderer); + int x = (int) (xPercent * (renderText->scrollWidth() - renderText->clientWidth())); - DBG_NAV_LOGD("x=%d y=%d xPercent=%g scrollW=%d clientW=%d", x, y, - xPercent, renderText->scrollWidth(), renderText->clientWidth()); renderText->setScrollLeft(x); renderText->setScrollTop(y); + focus->document()->frame()->selection()->recomputeCaretRect(); + LayerAndroid* layer = 0; + platformLayerIdFromNode(focus, &layer); + return absoluteContentRect(focus, layer); } void WebViewCore::setFocusControllerActive(bool active) @@ -2966,7 +2980,7 @@ void WebViewCore::setFocusControllerActive(bool active) void WebViewCore::saveDocumentState(WebCore::Frame* frame) { - if (!CacheBuilder::validNode(m_mainFrame, frame, 0)) + if (!validNode(m_mainFrame, frame, 0)) frame = m_mainFrame; WebCore::HistoryItem *item = frame->loader()->history()->currentItem(); @@ -2982,9 +2996,9 @@ void WebViewCore::saveDocumentState(WebCore::Frame* frame) static jobjectArray makeLabelArray(JNIEnv* env, const uint16_t** labels, size_t count) { jclass stringClass = env->FindClass("java/lang/String"); - LOG_ASSERT(stringClass, "Could not find java/lang/String"); + ALOG_ASSERT(stringClass, "Could not find java/lang/String"); jobjectArray array = env->NewObjectArray(count, stringClass, 0); - LOG_ASSERT(array, "Could not create new string array"); + ALOG_ASSERT(array, "Could not create new string array"); for (size_t i = 0; i < count; i++) { jobject newString = env->NewString(&labels[i][1], labels[i][0]); @@ -3007,11 +3021,19 @@ void WebViewCore::openFileChooser(PassRefPtr<WebCore::FileChooser> chooser) return; WTF::String acceptType = chooser->acceptTypes(); + WTF::String capture; + +#if ENABLE(MEDIA_CAPTURE) + capture = chooser->capture(); +#endif + jstring jAcceptType = wtfStringToJstring(env, acceptType, true); + jstring jCapture = wtfStringToJstring(env, capture, true); jstring jName = (jstring) env->CallObjectMethod( - javaObject.get(), m_javaGlue->m_openFileChooser, jAcceptType); + javaObject.get(), m_javaGlue->m_openFileChooser, jAcceptType, jCapture); checkException(env); env->DeleteLocalRef(jAcceptType); + env->DeleteLocalRef(jCapture); WTF::String wtfString = jstringToWtfString(env, jName); env->DeleteLocalRef(jName); @@ -3023,7 +3045,7 @@ void WebViewCore::openFileChooser(PassRefPtr<WebCore::FileChooser> chooser) void WebViewCore::listBoxRequest(WebCoreReply* reply, const uint16_t** labels, size_t count, const int enabled[], size_t enabledCount, bool multiple, const int selected[], size_t selectedCountOrSelection) { - LOG_ASSERT(m_javaGlue->m_obj, "No java widget associated with this view!"); + ALOG_ASSERT(m_javaGlue->m_obj, "No java widget associated with this view!"); JNIEnv* env = JSC::Bindings::getJNIEnv(); AutoJObject javaObject = m_javaGlue->object(env); @@ -3082,14 +3104,15 @@ bool WebViewCore::key(const PlatformKeyboardEvent& event) { WebCore::EventHandler* eventHandler; WebCore::Node* focusNode = currentFocus(); - DBG_NAV_LOGD("keyCode=%s unichar=%d focusNode=%p", - event.keyIdentifier().utf8().data(), event.unichar(), focusNode); if (focusNode) { WebCore::Frame* frame = focusNode->document()->frame(); - WebFrame* webFrame = WebFrame::getWebFrame(frame); eventHandler = frame->eventHandler(); VisibleSelection old = frame->selection()->selection(); + EditorClientAndroid* client = static_cast<EditorClientAndroid*>( + m_mainFrame->editor()->client()); + client->setUiGeneratedSelectionChange(true); bool handled = eventHandler->keyEvent(event); + client->setUiGeneratedSelectionChange(false); if (isContentEditable(focusNode)) { // keyEvent will return true even if the contentEditable did not // change its selection. In the case that it does not, we want to @@ -3099,33 +3122,53 @@ bool WebViewCore::key(const PlatformKeyboardEvent& event) } return handled; } else { - eventHandler = m_mainFrame->eventHandler(); + eventHandler = focusedFrame()->eventHandler(); } return eventHandler->keyEvent(event); } -// For when the user clicks the trackball, presses dpad center, or types into an -// unfocused textfield. In the latter case, 'fake' will be true -void WebViewCore::click(WebCore::Frame* frame, WebCore::Node* node, bool fake) { - if (!node) { - WebCore::IntPoint pt = m_mousePos; - pt.move(m_scrollOffsetX, m_scrollOffsetY); - WebCore::HitTestResult hitTestResult = m_mainFrame->eventHandler()-> - hitTestResultAtPoint(pt, false); - node = hitTestResult.innerNode(); - frame = node->document()->frame(); - DBG_NAV_LOGD("m_mousePos=(%d,%d) m_scrollOffset=(%d,%d) pt=(%d,%d)" - " node=%p", m_mousePos.x(), m_mousePos.y(), - m_scrollOffsetX, m_scrollOffsetY, pt.x(), pt.y(), node); - } - if (node) { - EditorClientAndroid* client - = static_cast<EditorClientAndroid*>( - m_mainFrame->editor()->client()); - client->setShouldChangeSelectedRange(false); - handleMouseClick(frame, node, fake); - client->setShouldChangeSelectedRange(true); +bool WebViewCore::chromeCanTakeFocus(FocusDirection direction) +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + AutoJObject javaObject = m_javaGlue->object(env); + if (!javaObject.get()) + return false; + return env->CallBooleanMethod(javaObject.get(), m_javaGlue->m_chromeCanTakeFocus, direction); +} + +void WebViewCore::chromeTakeFocus(FocusDirection direction) +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + AutoJObject javaObject = m_javaGlue->object(env); + if (!javaObject.get()) + return; + env->CallVoidMethod(javaObject.get(), m_javaGlue->m_chromeTakeFocus, direction); +} + +void WebViewCore::setInitialFocus(const WebCore::PlatformKeyboardEvent& platformEvent) +{ + Frame* frame = focusedFrame(); + Document* document = frame->document(); + if (document) + document->setFocusedNode(0); + FocusDirection direction; + switch (platformEvent.nativeVirtualKeyCode()) { + case AKEYCODE_DPAD_LEFT: + direction = FocusDirectionLeft; + break; + case AKEYCODE_DPAD_RIGHT: + direction = FocusDirectionRight; + break; + case AKEYCODE_DPAD_UP: + direction = FocusDirectionUp; + break; + default: + direction = FocusDirectionDown; + break; } + RefPtr<KeyboardEvent> webkitEvent = KeyboardEvent::create(platformEvent, 0); + m_mainFrame->page()->focusController()->setInitialFocus(direction, + webkitEvent.get()); } #if USE(ACCELERATED_COMPOSITING) @@ -3139,9 +3182,9 @@ GraphicsLayerAndroid* WebViewCore::graphicsRootLayer() const } #endif -bool WebViewCore::handleTouchEvent(int action, Vector<int>& ids, Vector<IntPoint>& points, int actionIndex, int metaState) +int WebViewCore::handleTouchEvent(int action, Vector<int>& ids, Vector<IntPoint>& points, int actionIndex, int metaState) { - bool preventDefault = false; + int flags = 0; #if USE(ACCELERATED_COMPOSITING) GraphicsLayerAndroid* rootLayer = graphicsRootLayer(); @@ -3182,18 +3225,10 @@ bool WebViewCore::handleTouchEvent(int action, Vector<int>& ids, Vector<IntPoint type = WebCore::TouchEnd; defaultTouchState = WebCore::PlatformTouchPoint::TouchStationary; break; - case 0x100: // WebViewCore.ACTION_LONGPRESS - type = WebCore::TouchLongPress; - defaultTouchState = WebCore::PlatformTouchPoint::TouchPressed; - break; - case 0x200: // WebViewCore.ACTION_DOUBLETAP - type = WebCore::TouchDoubleTap; - defaultTouchState = WebCore::PlatformTouchPoint::TouchPressed; - break; default: // We do not support other kinds of touch event inside WebCore // at the moment. - LOGW("Java passed a touch event type that we do not support in WebCore: %d", action); + ALOGW("Java passed a touch event type that we do not support in WebCore: %d", action); return 0; } @@ -3213,52 +3248,41 @@ bool WebViewCore::handleTouchEvent(int action, Vector<int>& ids, Vector<IntPoint } WebCore::PlatformTouchEvent te(ids, points, type, touchStates, metaState); - preventDefault = m_mainFrame->eventHandler()->handleTouchEvent(te); + if (m_mainFrame->eventHandler()->handleTouchEvent(te)) + flags |= TOUCH_FLAG_PREVENT_DEFAULT; + if (te.hitTouchHandler()) + flags |= TOUCH_FLAG_HIT_HANDLER; #endif #if USE(ACCELERATED_COMPOSITING) if (rootLayer) rootLayer->pauseDisplay(false); #endif - return preventDefault; + return flags; } -void WebViewCore::touchUp(int touchGeneration, - WebCore::Frame* frame, WebCore::Node* node, int x, int y) +bool WebViewCore::performMouseClick() { - if (touchGeneration == 0) { - // m_mousePos should be set in getTouchHighlightRects() - WebCore::HitTestResult hitTestResult = m_mainFrame->eventHandler()->hitTestResultAtPoint(m_mousePos, false); - node = hitTestResult.innerNode(); - if (node) - frame = node->document()->frame(); - else - frame = 0; - 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); - } else { - if (m_touchGeneration > touchGeneration) { - DBG_NAV_LOGD("m_touchGeneration=%d > touchGeneration=%d" - " x=%d y=%d", m_touchGeneration, touchGeneration, x, y); - return; // short circuit if a newer touch has been generated - } - // This moves m_mousePos to the correct place, and handleMouseClick uses - // m_mousePos to determine where the click happens. - moveMouse(frame, x, y); - m_lastGeneration = touchGeneration; - } - if (frame && CacheBuilder::validNode(m_mainFrame, frame, 0)) { - frame->loader()->resetMultipleFormSubmissionProtection(); - } - DBG_NAV_LOGD("touchGeneration=%d handleMouseClick frame=%p node=%p" - " x=%d y=%d", touchGeneration, frame, node, x, y); - handleMouseClick(frame, node, false); + WebCore::PlatformMouseEvent mouseDown(m_mouseClickPos, m_mouseClickPos, WebCore::LeftButton, + WebCore::MouseEventPressed, 1, false, false, false, false, + WTF::currentTime()); + // ignore the return from as it will return true if the hit point can trigger selection change + m_mainFrame->eventHandler()->handleMousePressEvent(mouseDown); + WebCore::PlatformMouseEvent mouseUp(m_mouseClickPos, m_mouseClickPos, WebCore::LeftButton, + WebCore::MouseEventReleased, 1, false, false, false, false, + WTF::currentTime()); + bool handled = m_mainFrame->eventHandler()->handleMouseReleaseEvent(mouseUp); + + WebCore::Node* focusNode = currentFocus(); + initializeTextInput(focusNode, false); + return handled; } // Check for the "x-webkit-soft-keyboard" attribute. If it is there and // set to hidden, do not show the soft keyboard. Node passed as a parameter // must not be null. static bool shouldSuppressKeyboard(const WebCore::Node* node) { - LOG_ASSERT(node, "node passed to shouldSuppressKeyboard cannot be null"); + ALOG_ASSERT(node, "node passed to shouldSuppressKeyboard cannot be null"); const NamedNodeMap* attributes = node->attributes(); if (!attributes) return false; size_t length = attributes->length(); @@ -3270,84 +3294,160 @@ static bool shouldSuppressKeyboard(const WebCore::Node* node) { return false; } -// Common code for both clicking with the trackball and touchUp -// Also used when typing into a non-focused textfield to give the textfield focus, -// in which case, 'fake' is set to true -bool WebViewCore::handleMouseClick(WebCore::Frame* framePtr, WebCore::Node* nodePtr, bool fake) -{ - bool valid = !framePtr || CacheBuilder::validNode(m_mainFrame, framePtr, nodePtr); - WebFrame* webFrame = WebFrame::getWebFrame(m_mainFrame); - if (valid && nodePtr) { - // Need to special case area tags because an image map could have an area element in the middle - // so when attempting to get the default, the point chosen would be follow the wrong link. - if (nodePtr->hasTagName(WebCore::HTMLNames::areaTag)) { - webFrame->setUserInitiatedAction(true); - nodePtr->dispatchSimulatedClick(0, true, true); - webFrame->setUserInitiatedAction(false); - DBG_NAV_LOG("area"); - return true; - } +WebViewCore::InputType WebViewCore::getInputType(Node* node) +{ + WebCore::RenderObject* renderer = node->renderer(); + if (!renderer) + return WebViewCore::NONE; + if (renderer->isTextArea()) + return WebViewCore::TEXT_AREA; + + if (node->hasTagName(WebCore::HTMLNames::inputTag)) { + HTMLInputElement* htmlInput = static_cast<HTMLInputElement*>(node); + if (htmlInput->isPasswordField()) + return WebViewCore::PASSWORD; + if (htmlInput->isSearchField()) + return WebViewCore::SEARCH; + if (htmlInput->isEmailField()) + return WebViewCore::EMAIL; + if (htmlInput->isNumberField()) + return WebViewCore::NUMBER; + if (htmlInput->isTelephoneField()) + return WebViewCore::TELEPHONE; + if (htmlInput->isTextField()) + return WebViewCore::NORMAL_TEXT_FIELD; } - if (!valid || !framePtr) - framePtr = m_mainFrame; - webFrame->setUserInitiatedAction(true); - WebCore::PlatformMouseEvent mouseDown(m_mousePos, m_mousePos, WebCore::LeftButton, - WebCore::MouseEventPressed, 1, false, false, false, false, - WTF::currentTime()); - // ignore the return from as it will return true if the hit point can trigger selection change - framePtr->eventHandler()->handleMousePressEvent(mouseDown); - WebCore::PlatformMouseEvent mouseUp(m_mousePos, m_mousePos, WebCore::LeftButton, - WebCore::MouseEventReleased, 1, false, false, false, false, - WTF::currentTime()); - bool handled = framePtr->eventHandler()->handleMouseReleaseEvent(mouseUp); - webFrame->setUserInitiatedAction(false); - // If the user clicked on a textfield, make the focusController active - // so we show the blinking cursor. - WebCore::Node* focusNode = currentFocus(); - DBG_NAV_LOGD("m_mousePos={%d,%d} focusNode=%p handled=%s", m_mousePos.x(), - m_mousePos.y(), focusNode, handled ? "true" : "false"); - if (focusNode) { - WebCore::RenderObject* renderer = focusNode->renderer(); - if (renderer && (renderer->isTextField() || renderer->isTextArea())) { - bool ime = !shouldSuppressKeyboard(focusNode) - && !(static_cast<WebCore::HTMLInputElement*>(focusNode))->readOnly(); - if (ime) { -#if ENABLE(WEB_AUTOFILL) - if (renderer->isTextField()) { - EditorClientAndroid* editorC = static_cast<EditorClientAndroid*>(framePtr->page()->editorClient()); - WebAutofill* autoFill = editorC->getAutofill(); - autoFill->formFieldFocused(static_cast<HTMLFormControlElement*>(focusNode)); - } -#endif - if (!fake) { - RenderTextControl* rtc - = static_cast<RenderTextControl*> (renderer); - // Force an update of the navcache as this will fire off a - // message to WebView that *must* have an updated focus. - m_frameCacheOutOfDate = true; - updateFrameCache(); - requestKeyboardWithSelection(focusNode, rtc->selectionStart(), - rtc->selectionEnd()); - } - } else if (!fake) { - requestKeyboard(false); - } - } else if (!fake){ - // If the selection is contentEditable, show the keyboard so the - // user can type. Otherwise hide the keyboard because no text - // input is needed. - if (isContentEditable(focusNode)) { - requestKeyboard(true); - } else if (!nodeIsPlugin(focusNode)) { - clearTextEntry(); - } + if (node->isContentEditable()) + return WebViewCore::TEXT_AREA; + + return WebViewCore::NONE; +} + +int WebViewCore::getMaxLength(Node* node) +{ + int maxLength = -1; + if (node->hasTagName(WebCore::HTMLNames::inputTag)) { + HTMLInputElement* htmlInput = static_cast<HTMLInputElement*>(node); + maxLength = htmlInput->maxLength(); + } + return maxLength; +} + +String WebViewCore::getFieldName(Node* node) +{ + String name; + if (node->hasTagName(WebCore::HTMLNames::inputTag)) { + HTMLInputElement* htmlInput = static_cast<HTMLInputElement*>(node); + name = htmlInput->name(); + } + return name; +} + +bool WebViewCore::isSpellCheckEnabled(Node* node) +{ + bool isEnabled = true; + if (node->isElementNode()) { + WebCore::Element* element = static_cast<WebCore::Element*>(node); + isEnabled = element->isSpellCheckingEnabled(); + } + return isEnabled; +} + +bool WebViewCore::isAutoCompleteEnabled(Node* node) +{ + bool isEnabled = false; + if (node->hasTagName(WebCore::HTMLNames::inputTag)) { + HTMLInputElement* htmlInput = static_cast<HTMLInputElement*>(node); + isEnabled = htmlInput->autoComplete(); + } + return isEnabled; +} + +WebCore::IntRect WebViewCore::absoluteContentRect(WebCore::Node* node, + LayerAndroid* layer) +{ + IntRect contentRect; + if (node) { + RenderObject* render = node->renderer(); + if (render && render->isBox() && !render->isBody()) { + IntPoint offset = convertGlobalContentToFrameContent(IntPoint(), + node->document()->frame()); + WebViewCore::layerToAbsoluteOffset(layer, offset); + + RenderBox* renderBox = toRenderBox(render); + contentRect = renderBox->absoluteContentBox(); + contentRect.move(-offset.x(), -offset.y()); } - } else if (!fake) { - // There is no focusNode, so the keyboard is not needed. - clearTextEntry(); } - return handled; + return contentRect; +} + +jobject WebViewCore::createTextFieldInitData(Node* node) +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + TextFieldInitDataGlue* classDef = m_textFieldInitDataGlue; + ScopedLocalRef<jclass> clazz(env, + env->FindClass("android/webkit/WebViewCore$TextFieldInitData")); + jobject initData = env->NewObject(clazz.get(), classDef->m_constructor); + env->SetIntField(initData, classDef->m_fieldPointer, + reinterpret_cast<int>(node)); + ScopedLocalRef<jstring> inputText(env, + wtfStringToJstring(env, getInputText(node), true)); + env->SetObjectField(initData, classDef->m_text, inputText.get()); + env->SetIntField(initData, classDef->m_type, getInputType(node)); + env->SetBooleanField(initData, classDef->m_isSpellCheckEnabled, + isSpellCheckEnabled(node)); + Document* document = node->document(); + PlatformKeyboardEvent tab(AKEYCODE_TAB, 0, 0, false, false, false, false); + PassRefPtr<KeyboardEvent> tabEvent = + KeyboardEvent::create(tab, document->defaultView()); + env->SetBooleanField(initData, classDef->m_isTextFieldNext, + isTextInput(document->nextFocusableNode(node, tabEvent.get()))); + env->SetBooleanField(initData, classDef->m_isTextFieldPrev, + isTextInput(document->previousFocusableNode(node, tabEvent.get()))); + env->SetBooleanField(initData, classDef->m_isAutoCompleteEnabled, + isAutoCompleteEnabled(node)); + ScopedLocalRef<jstring> fieldName(env, + wtfStringToJstring(env, getFieldName(node), false)); + env->SetObjectField(initData, classDef->m_name, fieldName.get()); + ScopedLocalRef<jstring> label(env, + wtfStringToJstring(env, requestLabel(document->frame(), node), false)); + env->SetObjectField(initData, classDef->m_label, label.get()); + env->SetIntField(initData, classDef->m_maxLength, getMaxLength(node)); + LayerAndroid* layer = 0; + int layerId = platformLayerIdFromNode(node, &layer); + IntRect bounds = absoluteContentRect(node, layer); + ScopedLocalRef<jobject> jbounds(env, intRectToRect(env, bounds)); + env->SetObjectField(initData, classDef->m_contentBounds, jbounds.get()); + env->SetIntField(initData, classDef->m_nodeLayerId, layerId); + IntRect contentRect; + RenderTextControl* rtc = toRenderTextControl(node); + if (rtc) { + contentRect.setWidth(rtc->scrollWidth()); + contentRect.setHeight(rtc->scrollHeight()); + contentRect.move(-rtc->scrollLeft(), -rtc->scrollTop()); + } + ScopedLocalRef<jobject> jcontentRect(env, intRectToRect(env, contentRect)); + env->SetObjectField(initData, classDef->m_contentRect, jcontentRect.get()); + return initData; +} + +void WebViewCore::initEditField(Node* node) +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + AutoJObject javaObject = m_javaGlue->object(env); + if (!javaObject.get()) + return; + m_textGeneration = 0; + int start = 0; + int end = 0; + getSelectionOffsets(node, start, end); + SelectText* selectText = createSelectText(focusedFrame()->selection()->selection()); + ScopedLocalRef<jobject> initData(env, createTextFieldInitData(node)); + env->CallVoidMethod(javaObject.get(), m_javaGlue->m_initEditField, + start, end, reinterpret_cast<int>(selectText), initData.get()); + checkException(env); } void WebViewCore::popupReply(int index) @@ -3368,28 +3468,99 @@ void WebViewCore::popupReply(const int* array, int count) } } -void WebViewCore::formDidBlur(const WebCore::Node* node) +// This is a slightly modified Node::nextNodeConsideringAtomicNodes() with the +// extra constraint of limiting the search to inside a containing parent +WebCore::Node* nextNodeWithinParent(WebCore::Node* parent, WebCore::Node* start) { - // If the blur is on a text input, keep track of the node so we can - // hide the soft keyboard when the new focus is set, if it is not a - // text input. - if (isTextInput(node)) - m_blurringNodePointer = reinterpret_cast<int>(node); + if (!isAtomicNode(start) && start->firstChild()) + return start->firstChild(); + if (start->nextSibling()) + return start->nextSibling(); + const Node *n = start; + while (n && !n->nextSibling()) { + n = n->parentNode(); + if (n == parent) + return 0; + } + if (n) + return n->nextSibling(); + return 0; } -void WebViewCore::focusNodeChanged(const WebCore::Node* newFocus) +void WebViewCore::initializeTextInput(WebCore::Node* node, bool fake) { + if (node) { + if (isTextInput(node)) { + bool showKeyboard = true; + initEditField(node); + WebCore::RenderTextControl* rtc = toRenderTextControl(node); + if (rtc && node->hasTagName(HTMLNames::inputTag)) { + HTMLInputElement* inputElement = static_cast<HTMLInputElement*>(node); + bool ime = !shouldSuppressKeyboard(node) && !inputElement->readOnly(); + if (ime) { +#if ENABLE(WEB_AUTOFILL) + if (rtc->isTextField()) { + Page* page = node->document()->page(); + EditorClient* editorClient = page->editorClient(); + EditorClientAndroid* androidEditor = + static_cast<EditorClientAndroid*>(editorClient); + WebAutofill* autoFill = androidEditor->getAutofill(); + autoFill->formFieldFocused(inputElement); + } +#endif + } else + showKeyboard = false; + } + if (!fake) + requestKeyboard(showKeyboard); + } else if (!fake && !nodeIsPlugin(node)) { + // not a text entry field, put away the keyboard. + clearTextEntry(); + } + } else if (!fake) { + // There is no focusNode, so the keyboard is not needed. + clearTextEntry(); + } +} + +void WebViewCore::focusNodeChanged(WebCore::Node* newFocus) +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + AutoJObject javaObject = m_javaGlue->object(env); + if (!javaObject.get()) + return; if (isTextInput(newFocus)) - m_shouldPaintCaret = true; - else if (m_blurringNodePointer) { - JNIEnv* env = JSC::Bindings::getJNIEnv(); - AutoJObject javaObject = m_javaGlue->object(env); - if (!javaObject.get()) - return; - env->CallVoidMethod(javaObject.get(), m_javaGlue->m_formDidBlur, m_blurringNodePointer); - checkException(env); - m_blurringNodePointer = 0; + initializeTextInput(newFocus, true); + HitTestResult focusHitResult; + focusHitResult.setInnerNode(newFocus); + focusHitResult.setInnerNonSharedNode(newFocus); + if (newFocus && newFocus->isLink() && newFocus->isElementNode()) { + focusHitResult.setURLElement(static_cast<Element*>(newFocus)); + if (newFocus->hasChildNodes() && !newFocus->hasTagName(HTMLNames::imgTag)) { + // Check to see if any of the children are images, and if so + // set them as the innerNode and innerNonSharedNode + // This will stop when it hits the first image. I'm not sure what + // should be done in the case of multiple images inside one anchor... + Node* nextNode = newFocus->firstChild(); + bool found = false; + while (nextNode) { + if (nextNode->hasTagName(HTMLNames::imgTag)) { + found = true; + break; + } + nextNode = nextNodeWithinParent(newFocus, nextNode); + } + if (found) { + focusHitResult.setInnerNode(nextNode); + focusHitResult.setInnerNonSharedNode(nextNode); + } + } } + AndroidHitTestResult androidHitTest(this, focusHitResult); + jobject jHitTestObj = androidHitTest.createJavaObject(env); + env->CallVoidMethod(javaObject.get(), m_javaGlue->m_focusNodeChanged, + reinterpret_cast<int>(newFocus), jHitTestObj); + env->DeleteLocalRef(jHitTestObj); } void WebViewCore::addMessageToConsole(const WTF::String& message, unsigned int lineNumber, const WTF::String& sourceID, int msgLevel) { @@ -3588,7 +3759,57 @@ WebViewCore::getWebViewJavaObject() AutoJObject javaObject = m_javaGlue->object(env); if (!javaObject.get()) return 0; - return env->GetObjectField(javaObject.get(), gWebViewCoreFields.m_webView); + return env->CallObjectMethod(javaObject.get(), m_javaGlue->m_getWebView); +} + +RenderTextControl* WebViewCore::toRenderTextControl(Node* node) +{ + RenderTextControl* rtc = 0; + RenderObject* renderer = node->renderer(); + if (renderer && renderer->isTextControl()) { + rtc = WebCore::toRenderTextControl(renderer); + } + return rtc; +} + +void WebViewCore::getSelectionOffsets(Node* node, int& start, int& end) +{ + RenderTextControl* rtc = toRenderTextControl(node); + if (rtc) { + start = rtc->selectionStart(); + end = rtc->selectionEnd(); + } else { + // It must be content editable field. + Document* document = node->document(); + Frame* frame = document->frame(); + SelectionController* selector = frame->selection(); + Position selectionStart = selector->start(); + Position selectionEnd = selector->end(); + Position startOfNode = firstPositionInNode(node); + RefPtr<Range> startRange = Range::create(document, startOfNode, + selectionStart); + start = TextIterator::rangeLength(startRange.get(), true); + RefPtr<Range> endRange = Range::create(document, startOfNode, + selectionEnd); + end = TextIterator::rangeLength(endRange.get(), true); + } +} + +String WebViewCore::getInputText(Node* node) +{ + String text; + WebCore::RenderTextControl* renderText = toRenderTextControl(node); + if (renderText) + text = renderText->text(); + else { + // It must be content editable field. + Position start = firstPositionInNode(node); + Position end = lastPositionInNode(node); + VisibleSelection allEditableText(start, end); + if (allEditableText.isRange()) + text = allEditableText.firstRange()->text(); + } + return text; } void WebViewCore::updateTextSelection() @@ -3597,16 +3818,33 @@ void WebViewCore::updateTextSelection() AutoJObject javaObject = m_javaGlue->object(env); if (!javaObject.get()) return; - WebCore::Node* focusNode = currentFocus(); - if (!focusNode) + VisibleSelection selection = focusedFrame()->selection()->selection(); + int start = 0; + int end = 0; + if (selection.isCaretOrRange()) + getSelectionOffsets(selection.start().anchorNode(), start, end); + SelectText* selectText = createSelectText(selection); + env->CallVoidMethod(javaObject.get(), + m_javaGlue->m_updateTextSelection, reinterpret_cast<int>(currentFocus()), + start, end, m_textGeneration, reinterpret_cast<int>(selectText)); + checkException(env); +} + +void WebViewCore::updateTextSizeAndScroll(WebCore::Node* node) +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + AutoJObject javaObject = m_javaGlue->object(env); + if (!javaObject.get()) return; - RenderObject* renderer = focusNode->renderer(); - if (!renderer || (!renderer->isTextArea() && !renderer->isTextField())) + RenderTextControl* rtc = toRenderTextControl(node); + if (!rtc) return; - RenderTextControl* rtc = static_cast<RenderTextControl*>(renderer); - env->CallVoidMethod(javaObject.get(), - m_javaGlue->m_updateTextSelection, reinterpret_cast<int>(focusNode), - rtc->selectionStart(), rtc->selectionEnd(), m_textGeneration); + int width = rtc->scrollWidth(); + int height = rtc->contentHeight(); + int scrollX = rtc->scrollLeft(); + int scrollY = rtc->scrollTop(); + env->CallVoidMethod(javaObject.get(), m_javaGlue->m_updateTextSizeAndScroll, + reinterpret_cast<int>(node), width, height, scrollX, scrollY); checkException(env); } @@ -3650,11 +3888,18 @@ void WebViewCore::setBackgroundColor(SkColor c) // need (int) cast to find the right constructor WebCore::Color bcolor((int)SkColorGetR(c), (int)SkColorGetG(c), (int)SkColorGetB(c), (int)SkColorGetA(c)); + + if (view->baseBackgroundColor() == bcolor) + return; + view->setBaseBackgroundColor(bcolor); // Background color of 0 indicates we want a transparent background if (c == 0) view->setTransparent(true); + + //invalidate so the new color is shown + contentInvalidateAll(); } jclass WebViewCore::getPluginClass(const WTF::String& libName, const char* className) @@ -3780,21 +4025,6 @@ void WebViewCore::keepScreenOn(bool screenOn) { m_screenOnCounter--; } -bool WebViewCore::validNodeAndBounds(Frame* frame, Node* node, - const IntRect& originalAbsoluteBounds) -{ - bool valid = CacheBuilder::validNode(m_mainFrame, frame, node); - if (!valid) - return false; - RenderObject* renderer = node->renderer(); - if (!renderer) - return false; - IntRect absBounds = node->hasTagName(HTMLNames::areaTag) - ? CacheBuilder::getAreaRect(static_cast<HTMLAreaElement*>(node)) - : renderer->absoluteBoundingBoxRect(); - return absBounds == originalAbsoluteBounds; -} - void WebViewCore::showRect(int left, int top, int width, int height, int contentWidth, int contentHeight, float xPercentInDoc, float xPercentInView, float yPercentInDoc, float yPercentInView) @@ -3848,6 +4078,20 @@ void WebViewCore::enterFullscreenForVideoLayer(int layerId, const WTF::String& u return; jstring jUrlStr = wtfStringToJstring(env, url); env->CallVoidMethod(javaObject.get(), m_javaGlue->m_enterFullscreenForVideoLayer, layerId, jUrlStr); + m_fullscreenVideoMode = true; + checkException(env); +} + +void WebViewCore::exitFullscreenVideo() +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + AutoJObject javaObject = m_javaGlue->object(env); + if (!javaObject.get()) + return; + if (m_fullscreenVideoMode) { + env->CallVoidMethod(javaObject.get(), m_javaGlue->m_exitFullscreenVideo); + m_fullscreenVideoMode = false; + } checkException(env); } #endif @@ -3873,7 +4117,6 @@ bool WebViewCore::drawIsPaused() const return false; } -#if USE(CHROME_NETWORK_STACK) void WebViewCore::setWebRequestContextUserAgent() { // We cannot create a WebRequestContext, because we might not know it this is a private tab or not yet @@ -3901,7 +4144,6 @@ WebRequestContext* WebViewCore::webRequestContext() } return m_webRequestContext.get(); } -#endif void WebViewCore::scrollRenderLayer(int layer, const SkRect& rect) { @@ -3922,189 +4164,370 @@ void WebViewCore::scrollRenderLayer(int layer, const SkRect& rect) if (!owner) return; - if (owner->stackingContext()) + if (owner->isRootLayer()) { + FrameView* view = owner->renderer()->frame()->view(); + IntPoint pt(rect.fLeft, rect.fTop); + view->setScrollPosition(pt); + } else owner->scrollToOffset(rect.fLeft, rect.fTop); #endif } +Vector<VisibleSelection> WebViewCore::getTextRanges( + int startX, int startY, int endX, int endY) +{ + // These are the positions of the selection handles, + // which reside below the line that they are selecting. + // Use the vertical position higher, which will include + // the selected text. + startY--; + endY--; + VisiblePosition startSelect = visiblePositionForContentPoint(startX, startY); + VisiblePosition endSelect = visiblePositionForContentPoint(endX, endY); + Position start = startSelect.deepEquivalent(); + Position end = endSelect.deepEquivalent(); + Vector<VisibleSelection> ranges; + if (!start.isNull() && !end.isNull()) { + if (comparePositions(start, end) > 0) { + swap(start, end); // RTL start/end positions may be swapped + } + Position nextRangeStart = start; + Position previousRangeEnd; + do { + VisibleSelection selection(nextRangeStart, end); + ranges.append(selection); + previousRangeEnd = selection.end(); + nextRangeStart = nextCandidate(previousRangeEnd); + } while (comparePositions(previousRangeEnd, end) < 0); + } + return ranges; +} + +void WebViewCore::deleteText(int startX, int startY, int endX, int endY) +{ + Vector<VisibleSelection> ranges = + getTextRanges(startX, startY, endX, endY); + + EditorClientAndroid* client = static_cast<EditorClientAndroid*>( + m_mainFrame->editor()->client()); + client->setUiGeneratedSelectionChange(true); + + SelectionController* selector = m_mainFrame->selection(); + for (size_t i = 0; i < ranges.size(); i++) { + const VisibleSelection& selection = ranges[i]; + if (selection.isContentEditable()) { + selector->setSelection(selection, CharacterGranularity); + Document* document = selection.start().anchorNode()->document(); + WebCore::TypingCommand::deleteSelection(document, 0); + } + } + client->setUiGeneratedSelectionChange(false); +} + +void WebViewCore::insertText(const WTF::String &text) +{ + WebCore::Node* focus = currentFocus(); + if (!focus || !isTextInput(focus)) + return; + + Document* document = focus->document(); + + EditorClientAndroid* client = static_cast<EditorClientAndroid*>( + m_mainFrame->editor()->client()); + if (!client) + return; + client->setUiGeneratedSelectionChange(true); + WebCore::TypingCommand::insertText(document, text, + TypingCommand::PreventSpellChecking); + client->setUiGeneratedSelectionChange(false); +} + +void WebViewCore::resetFindOnPage() +{ + m_searchText.truncate(0); + m_matchCount = 0; + m_activeMatchIndex = 0; + m_activeMatch = 0; +} + +int WebViewCore::findTextOnPage(const WTF::String &text) +{ + resetFindOnPage(); // reset even if parameters are bad + + WebCore::Frame* frame = m_mainFrame; + if (!frame) + return 0; + + m_searchText = text; + FindOptions findOptions = WebCore::CaseInsensitive; + + do { + frame->document()->markers()->removeMarkers(DocumentMarker::TextMatch); + m_matchCount += frame->editor()->countMatchesForText(text, findOptions, + 0, true); + frame->editor()->setMarkedTextMatchesAreHighlighted(true); + frame = frame->tree()->traverseNextWithWrap(false); + } while (frame); + m_activeMatchIndex = m_matchCount - 1; // prime first findNext + return m_matchCount; +} + +int WebViewCore::findNextOnPage(bool forward) +{ + if (!m_mainFrame) + return -1; + if (!m_matchCount) + return -1; + + EditorClientAndroid* client = static_cast<EditorClientAndroid*>( + m_mainFrame->editor()->client()); + client->setUiGeneratedSelectionChange(true); + + // Clear previous active match. + if (m_activeMatch) { + m_mainFrame->document()->markers()->setMarkersActive( + m_activeMatch.get(), false); + } + + FindOptions findOptions = WebCore::CaseInsensitive + | WebCore::StartInSelection | WebCore::WrapAround; + if (!forward) + findOptions |= WebCore::Backwards; + + // Start from the previous active match. + if (m_activeMatch) { + m_mainFrame->selection()->setSelection(m_activeMatch.get()); + } + + bool found = m_mainFrame->editor()->findString(m_searchText, findOptions); + if (found) { + VisibleSelection selection(m_mainFrame->selection()->selection()); + if (selection.isNone() || selection.start() == selection.end()) { + // Temporary workaround for findString() refusing to select text + // marked "-webkit-user-select: none". + m_activeMatchIndex = 0; + m_activeMatch = 0; + } else { + // Mark current match "active". + if (forward) { + ++m_activeMatchIndex; + if (m_activeMatchIndex == m_matchCount) + m_activeMatchIndex = 0; + } else { + if (m_activeMatchIndex == 0) + m_activeMatchIndex = m_matchCount; + --m_activeMatchIndex; + } + m_activeMatch = selection.firstRange(); + m_mainFrame->document()->markers()->setMarkersActive( + m_activeMatch.get(), true); + m_mainFrame->selection()->revealSelection( + ScrollAlignment::alignCenterIfNeeded, true); + } + } + + // Clear selection so it doesn't display. + m_mainFrame->selection()->clear(); + client->setUiGeneratedSelectionChange(false); + return m_activeMatchIndex; +} + +String WebViewCore::getText(int startX, int startY, int endX, int endY) +{ + String text; + + Vector<VisibleSelection> ranges = + getTextRanges(startX, startY, endX, endY); + + for (size_t i = 0; i < ranges.size(); i++) { + const VisibleSelection& selection = ranges[i]; + if (selection.isRange()) { + PassRefPtr<Range> range = selection.firstRange(); + String textInRange = range->text(); + if (textInRange.length() > 0) { + if (text.length() > 0) + text.append('\n'); + text.append(textInRange); + } + } + } + + return text; +} + +/** + * Read the persistent locale. + */ +void WebViewCore::getLocale(String& language, String& region) +{ + char propLang[PROPERTY_VALUE_MAX], propRegn[PROPERTY_VALUE_MAX]; + + property_get("persist.sys.language", propLang, ""); + property_get("persist.sys.country", propRegn, ""); + if (*propLang == 0 && *propRegn == 0) { + /* Set to ro properties, default is en_US */ + property_get("ro.product.locale.language", propLang, "en"); + property_get("ro.product.locale.region", propRegn, "US"); + } + language = String(propLang, 2); + region = String(propRegn, 2); +} + +void WebViewCore::updateLocale() +{ + static String prevLang; + static String prevRegn; + String language; + String region; + + getLocale(language, region); + + if ((language != prevLang) || (region != prevRegn)) { + prevLang = language; + prevRegn = region; + GlyphPageTreeNode::resetRoots(); + fontCache()->invalidate(); + } +} + //---------------------------------------------------------------------- // Native JNI methods //---------------------------------------------------------------------- -static void RevealSelection(JNIEnv *env, jobject obj) +static void RevealSelection(JNIEnv* env, jobject obj, jint nativeClass) { - GET_NATIVE_VIEW(env, obj)->revealSelection(); + reinterpret_cast<WebViewCore*>(nativeClass)->revealSelection(); } -static jstring RequestLabel(JNIEnv *env, jobject obj, int framePointer, - int nodePointer) +static jstring RequestLabel(JNIEnv* env, jobject obj, jint nativeClass, + int framePointer, int nodePointer) { - return wtfStringToJstring(env, GET_NATIVE_VIEW(env, obj)->requestLabel( + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + return wtfStringToJstring(env, viewImpl->requestLabel( (WebCore::Frame*) framePointer, (WebCore::Node*) nodePointer)); } -static void ClearContent(JNIEnv *env, jobject obj) +static void ClearContent(JNIEnv* env, jobject obj, jint nativeClass) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); viewImpl->clearContent(); } -static void UpdateFrameCacheIfLoading(JNIEnv *env, jobject obj) -{ - GET_NATIVE_VIEW(env, obj)->updateFrameCacheIfLoading(); -} - -static void SetSize(JNIEnv *env, jobject obj, jint width, jint height, - jint textWrapWidth, jfloat scale, jint screenWidth, jint screenHeight, - jint anchorX, jint anchorY, jboolean ignoreHeight) +static void SetSize(JNIEnv* env, jobject obj, jint nativeClass, jint width, + jint height, jint textWrapWidth, jfloat scale, jint screenWidth, + jint screenHeight, jint anchorX, jint anchorY, jboolean ignoreHeight) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOGV("webviewcore::nativeSetSize(%u %u)\n viewImpl: %p", (unsigned)width, (unsigned)height, viewImpl); - LOG_ASSERT(viewImpl, "viewImpl not set in nativeSetSize"); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + ALOGV("webviewcore::nativeSetSize(%u %u)\n viewImpl: %p", (unsigned)width, (unsigned)height, viewImpl); + ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSetSize"); viewImpl->setSizeScreenWidthAndScale(width, height, textWrapWidth, scale, screenWidth, screenHeight, anchorX, anchorY, ignoreHeight); } -static void SetScrollOffset(JNIEnv *env, jobject obj, jint gen, jboolean sendScrollEvent, jint x, jint y) +static void SetScrollOffset(JNIEnv* env, jobject obj, jint nativeClass, + jboolean sendScrollEvent, jint x, jint y) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "need viewImpl"); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + ALOG_ASSERT(viewImpl, "need viewImpl"); - viewImpl->setScrollOffset(gen, sendScrollEvent, x, y); + viewImpl->setScrollOffset(sendScrollEvent, x, y); } -static void SetGlobalBounds(JNIEnv *env, jobject obj, jint x, jint y, jint h, - jint v) +static void SetGlobalBounds(JNIEnv* env, jobject obj, jint nativeClass, + jint x, jint y, jint h, jint v) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "need viewImpl"); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + ALOG_ASSERT(viewImpl, "need viewImpl"); viewImpl->setGlobalBounds(x, y, h, v); } -static jboolean Key(JNIEnv *env, jobject obj, jint keyCode, jint unichar, - jint repeatCount, jboolean isShift, jboolean isAlt, jboolean isSym, - jboolean isDown) +static jboolean Key(JNIEnv* env, jobject obj, jint nativeClass, jint keyCode, + jint unichar, jint repeatCount, jboolean isShift, jboolean isAlt, + jboolean isSym, jboolean isDown) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - return GET_NATIVE_VIEW(env, obj)->key(PlatformKeyboardEvent(keyCode, + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + return viewImpl->key(PlatformKeyboardEvent(keyCode, unichar, repeatCount, isDown, isShift, isAlt, isSym)); } -static void Click(JNIEnv *env, jobject obj, int framePtr, int nodePtr, jboolean fake) +static void SetInitialFocus(JNIEnv* env, jobject obj, jint nativeClass, + jint keyDirection) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in Click"); - - viewImpl->click(reinterpret_cast<WebCore::Frame*>(framePtr), - reinterpret_cast<WebCore::Node*>(nodePtr), fake); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + viewImpl->setInitialFocus(PlatformKeyboardEvent(keyDirection, + 0, 0, false, false, false, false)); } -static void ContentInvalidateAll(JNIEnv *env, jobject obj) +static void ContentInvalidateAll(JNIEnv* env, jobject obj, jint nativeClass) { - GET_NATIVE_VIEW(env, obj)->contentInvalidateAll(); + reinterpret_cast<WebViewCore*>(nativeClass)->contentInvalidateAll(); } -static void DeleteSelection(JNIEnv *env, jobject obj, jint start, jint end, - jint textGeneration) +static void DeleteSelection(JNIEnv* env, jobject obj, jint nativeClass, + jint start, jint end, jint textGeneration) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); viewImpl->deleteSelection(start, end, textGeneration); } -static void SetSelection(JNIEnv *env, jobject obj, jint start, jint end) +static void SetSelection(JNIEnv* env, jobject obj, jint nativeClass, + jint start, jint end) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); viewImpl->setSelection(start, end); } -static jstring ModifySelection(JNIEnv *env, jobject obj, jint direction, jint granularity) +static jstring ModifySelection(JNIEnv* env, jobject obj, jint nativeClass, + jint direction, jint granularity) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); String selectionString = viewImpl->modifySelection(direction, granularity); return wtfStringToJstring(env, selectionString); } -static void ReplaceTextfieldText(JNIEnv *env, jobject obj, +static void ReplaceTextfieldText(JNIEnv* env, jobject obj, jint nativeClass, jint oldStart, jint oldEnd, jstring replace, jint start, jint end, jint textGeneration) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); WTF::String webcoreString = jstringToWtfString(env, replace); viewImpl->replaceTextfieldText(oldStart, oldEnd, webcoreString, start, end, textGeneration); } -static void PassToJs(JNIEnv *env, jobject obj, +static void PassToJs(JNIEnv* env, jobject obj, jint nativeClass, jint generation, jstring currentText, jint keyCode, jint keyValue, jboolean down, jboolean cap, jboolean fn, jboolean sym) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif WTF::String current = jstringToWtfString(env, currentText); - GET_NATIVE_VIEW(env, obj)->passToJs(generation, current, + reinterpret_cast<WebViewCore*>(nativeClass)->passToJs(generation, current, PlatformKeyboardEvent(keyCode, keyValue, 0, down, cap, fn, sym)); } -static void ScrollFocusedTextInput(JNIEnv *env, jobject obj, jfloat xPercent, - jint y) +static void ScrollFocusedTextInput(JNIEnv* env, jobject obj, jint nativeClass, + jfloat xPercent, jint y, jobject contentBounds) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - viewImpl->scrollFocusedTextInput(xPercent, y); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + IntRect bounds = viewImpl->scrollFocusedTextInput(xPercent, y); + if (contentBounds) + GraphicsJNI::irect_to_jrect(bounds, env, contentBounds); } -static void SetFocusControllerActive(JNIEnv *env, jobject obj, jboolean active) +static void SetFocusControllerActive(JNIEnv* env, jobject obj, jint nativeClass, + jboolean active) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - LOGV("webviewcore::nativeSetFocusControllerActive()\n"); - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in nativeSetFocusControllerActive"); + ALOGV("webviewcore::nativeSetFocusControllerActive()\n"); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSetFocusControllerActive"); viewImpl->setFocusControllerActive(active); } -static void SaveDocumentState(JNIEnv *env, jobject obj, jint frame) +static void SaveDocumentState(JNIEnv* env, jobject obj, jint nativeClass) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - LOGV("webviewcore::nativeSaveDocumentState()\n"); - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in nativeSaveDocumentState"); - viewImpl->saveDocumentState((WebCore::Frame*) frame); + ALOGV("webviewcore::nativeSaveDocumentState()\n"); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSaveDocumentState"); + viewImpl->saveDocumentState(viewImpl->focusedFrame()); } void WebViewCore::addVisitedLink(const UChar* string, int length) @@ -4113,53 +4536,26 @@ void WebViewCore::addVisitedLink(const UChar* string, int length) m_groupForVisitedLinks->addVisitedLink(string, length); } -static bool UpdateLayers(JNIEnv *env, jobject obj, jint nativeClass, jint jbaseLayer) -{ - WebViewCore* viewImpl = (WebViewCore*) nativeClass; - BaseLayerAndroid* baseLayer = (BaseLayerAndroid*) jbaseLayer; - if (baseLayer) { - LayerAndroid* root = static_cast<LayerAndroid*>(baseLayer->getChild(0)); - if (root) - return viewImpl->updateLayers(root); - } - return true; -} - -static void NotifyAnimationStarted(JNIEnv *env, jobject obj, jint nativeClass) +static void NotifyAnimationStarted(JNIEnv* env, jobject obj, jint nativeClass) { WebViewCore* viewImpl = (WebViewCore*) nativeClass; viewImpl->notifyAnimationStarted(); } -static jint RecordContent(JNIEnv *env, jobject obj, jobject region, jobject pt) +static jint RecordContent(JNIEnv* env, jobject obj, jint nativeClass, jobject pt) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - SkRegion* nativeRegion = GraphicsJNI::getNativeRegion(env, region); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); SkIPoint nativePt; - BaseLayerAndroid* result = viewImpl->recordContent(nativeRegion, &nativePt); + BaseLayerAndroid* result = viewImpl->recordContent(&nativePt); GraphicsJNI::ipoint_to_jpoint(nativePt, env, pt); return reinterpret_cast<jint>(result); } -static void SplitContent(JNIEnv *env, jobject obj, jint content) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - viewImpl->splitContent(reinterpret_cast<PictureSet*>(content)); -} - -static void SendListBoxChoice(JNIEnv* env, jobject obj, jint choice) +static void SendListBoxChoice(JNIEnv* env, jobject obj, jint nativeClass, + jint choice) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoice"); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoice"); viewImpl->popupReply(choice); } @@ -4169,14 +4565,11 @@ static void SendListBoxChoice(JNIEnv* env, jobject obj, jint choice) // number of items in the average multiple-select listbox. #define PREPARED_LISTBOX_STORAGE 10 -static void SendListBoxChoices(JNIEnv* env, jobject obj, jbooleanArray jArray, - jint size) +static void SendListBoxChoices(JNIEnv* env, jobject obj, jint nativeClass, + jbooleanArray jArray, jint size) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoices"); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + ALOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoices"); jboolean* ptrArray = env->GetBooleanArrayElements(jArray, 0); SkAutoSTMalloc<PREPARED_LISTBOX_STORAGE, int> storage(size); int* array = storage.get(); @@ -4190,21 +4583,19 @@ static void SendListBoxChoices(JNIEnv* env, jobject obj, jbooleanArray jArray, viewImpl->popupReply(array, count); } -static jstring FindAddress(JNIEnv *env, jobject obj, jstring addr, - jboolean caseInsensitive) +// TODO: Move this to WebView.cpp since it is only needed there +static jstring FindAddress(JNIEnv* env, jobject obj, jstring addr, + jboolean caseInsensitive) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif if (!addr) return 0; int length = env->GetStringLength(addr); if (!length) return 0; const jchar* addrChars = env->GetStringChars(addr, 0); - int start, end; - bool success = CacheBuilder::FindAddress(addrChars, length, - &start, &end, caseInsensitive) == CacheBuilder::FOUND_COMPLETE; + size_t start, end; + AddressDetector detector; + bool success = detector.FindContent(addrChars, addrChars + length, &start, &end); jstring ret = 0; if (success) ret = env->NewString(addrChars + start, end - start); @@ -4212,15 +4603,12 @@ static jstring FindAddress(JNIEnv *env, jobject obj, jstring addr, return ret; } -static jboolean HandleTouchEvent(JNIEnv *env, jobject obj, jint action, jintArray idArray, - jintArray xArray, jintArray yArray, - jint count, jint actionIndex, jint metaState) +static jint HandleTouchEvent(JNIEnv* env, jobject obj, jint nativeClass, + jint action, jintArray idArray, jintArray xArray, jintArray yArray, + jint count, jint actionIndex, jint metaState) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); jint* ptrIdArray = env->GetIntArrayElements(idArray, 0); jint* ptrXArray = env->GetIntArrayElements(xArray, 0); jint* ptrYArray = env->GetIntArrayElements(yArray, 0); @@ -4238,105 +4626,53 @@ static jboolean HandleTouchEvent(JNIEnv *env, jobject obj, jint action, jintArra return viewImpl->handleTouchEvent(action, ids, points, actionIndex, metaState); } -static void TouchUp(JNIEnv *env, jobject obj, jint touchGeneration, - jint frame, jint node, jint x, jint y) +static bool MouseClick(JNIEnv* env, jobject obj, jint nativeClass) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); - viewImpl->touchUp(touchGeneration, - (WebCore::Frame*) frame, (WebCore::Node*) node, x, y); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + return viewImpl->performMouseClick(); } -static jstring RetrieveHref(JNIEnv *env, jobject obj, jint x, jint y) +static jstring RetrieveHref(JNIEnv* env, jobject obj, jint nativeClass, + jint x, jint y) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); WTF::String result = viewImpl->retrieveHref(x, y); if (!result.isEmpty()) return wtfStringToJstring(env, result); return 0; } -static jstring RetrieveAnchorText(JNIEnv *env, jobject obj, jint x, jint y) +static jstring RetrieveAnchorText(JNIEnv* env, jobject obj, jint nativeClass, + jint x, jint y) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); WTF::String result = viewImpl->retrieveAnchorText(x, y); if (!result.isEmpty()) return wtfStringToJstring(env, result); return 0; } -static jstring RetrieveImageSource(JNIEnv *env, jobject obj, jint x, jint y) -{ - WTF::String result = GET_NATIVE_VIEW(env, obj)->retrieveImageSource(x, y); - return !result.isEmpty() ? wtfStringToJstring(env, result) : 0; -} - -static void StopPaintingCaret(JNIEnv *env, jobject obj) -{ - GET_NATIVE_VIEW(env, obj)->setShouldPaintCaret(false); -} - -static void MoveFocus(JNIEnv *env, jobject obj, jint framePtr, jint nodePtr) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); - viewImpl->moveFocus((WebCore::Frame*) framePtr, (WebCore::Node*) nodePtr); -} - -static void MoveMouse(JNIEnv *env, jobject obj, jint frame, +static jstring RetrieveImageSource(JNIEnv* env, jobject obj, jint nativeClass, jint x, jint y) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); - viewImpl->moveMouse((WebCore::Frame*) frame, x, y); -} - -static void MoveMouseIfLatest(JNIEnv *env, jobject obj, jint moveGeneration, - jint frame, jint x, jint y) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); - viewImpl->moveMouseIfLatest(moveGeneration, - (WebCore::Frame*) frame, x, y); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + WTF::String result = viewImpl->retrieveImageSource(x, y); + return !result.isEmpty() ? wtfStringToJstring(env, result) : 0; } -static void UpdateFrameCache(JNIEnv *env, jobject obj) +static void MoveMouse(JNIEnv* env, jobject obj, jint nativeClass, jint x, jint y) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); - viewImpl->updateFrameCache(); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); + viewImpl->moveMouse(x, y); } -static jint GetContentMinPrefWidth(JNIEnv *env, jobject obj) +static jint GetContentMinPrefWidth(JNIEnv* env, jobject obj, jint nativeClass) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); WebCore::Frame* frame = viewImpl->mainFrame(); if (frame) { @@ -4351,13 +4687,11 @@ static jint GetContentMinPrefWidth(JNIEnv *env, jobject obj) return 0; } -static void SetViewportSettingsFromNative(JNIEnv *env, jobject obj) +static void SetViewportSettingsFromNative(JNIEnv* env, jobject obj, + jint nativeClass) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); WebCore::Settings* s = viewImpl->mainFrame()->page()->settings(); if (!s) @@ -4374,66 +4708,49 @@ static void SetViewportSettingsFromNative(JNIEnv *env, jobject obj) #endif } -static void SetBackgroundColor(JNIEnv *env, jobject obj, jint color) +static void SetBackgroundColor(JNIEnv* env, jobject obj, jint nativeClass, + jint color) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); viewImpl->setBackgroundColor((SkColor) color); } -static void DumpDomTree(JNIEnv *env, jobject obj, jboolean useFile) +static void DumpDomTree(JNIEnv* env, jobject obj, jint nativeClass, + jboolean useFile) { - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); viewImpl->dumpDomTree(useFile); } -static void DumpRenderTree(JNIEnv *env, jobject obj, jboolean useFile) +static void DumpRenderTree(JNIEnv* env, jobject obj, jint nativeClass, + jboolean useFile) { - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); viewImpl->dumpRenderTree(useFile); } -static void DumpNavTree(JNIEnv *env, jobject obj) -{ - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); - - viewImpl->dumpNavTree(); -} - -static void DumpV8Counters(JNIEnv*, jobject) +static void SetJsFlags(JNIEnv* env, jobject obj, jint nativeClass, jstring flags) { -#if USE(V8) -#ifdef ANDROID_INSTRUMENT - V8Counters::dumpCounters(); -#endif -#endif -} - -static void SetJsFlags(JNIEnv *env, jobject obj, jstring flags) -{ -#if USE(V8) WTF::String flagsString = jstringToWtfString(env, flags); WTF::CString utf8String = flagsString.utf8(); WebCore::ScriptController::setFlags(utf8String.data(), utf8String.length()); -#endif } // Called from the Java side to set a new quota for the origin or new appcache // max size in response to a notification that the original quota was exceeded or // that the appcache has reached its maximum size. -static void SetNewStorageLimit(JNIEnv* env, jobject obj, jlong quota) { +static void SetNewStorageLimit(JNIEnv* env, jobject obj, jint nativeClass, + jlong quota) +{ #if ENABLE(DATABASE) || ENABLE(OFFLINE_WEB_APPLICATIONS) - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); Frame* frame = viewImpl->mainFrame(); // The main thread is blocked awaiting this response, so now we can wake it @@ -4444,93 +4761,102 @@ static void SetNewStorageLimit(JNIEnv* env, jobject obj, jlong quota) { } // Called from Java to provide a Geolocation permission state for the specified origin. -static void GeolocationPermissionsProvide(JNIEnv* env, jobject obj, jstring origin, jboolean allow, jboolean remember) { - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); +static void GeolocationPermissionsProvide(JNIEnv* env, jobject obj, + jint nativeClass, jstring origin, jboolean allow, jboolean remember) +{ + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); Frame* frame = viewImpl->mainFrame(); ChromeClientAndroid* chromeClient = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client()); chromeClient->provideGeolocationPermissions(jstringToWtfString(env, origin), allow, remember); } -static void RegisterURLSchemeAsLocal(JNIEnv* env, jobject obj, jstring scheme) { -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif +static void RegisterURLSchemeAsLocal(JNIEnv* env, jobject obj, jint nativeClass, + jstring scheme) +{ WebCore::SchemeRegistry::registerURLSchemeAsLocal(jstringToWtfString(env, scheme)); } -static bool FocusBoundsChanged(JNIEnv* env, jobject obj) +static bool FocusBoundsChanged(JNIEnv* env, jobject obj, jint nativeClass) { - return GET_NATIVE_VIEW(env, obj)->focusBoundsChanged(); + return reinterpret_cast<WebViewCore*>(nativeClass)->focusBoundsChanged(); } -static void SetIsPaused(JNIEnv* env, jobject obj, jboolean isPaused) +static void SetIsPaused(JNIEnv* env, jobject obj, jint nativeClass, + jboolean isPaused) { // tell the webcore thread to stop thinking while we do other work // (selection and scrolling). This has nothing to do with the lifecycle // pause and resume. - GET_NATIVE_VIEW(env, obj)->setIsPaused(isPaused); + reinterpret_cast<WebViewCore*>(nativeClass)->setIsPaused(isPaused); } -static void Pause(JNIEnv* env, jobject obj) +static void Pause(JNIEnv* env, jobject obj, jint nativeClass) { // This is called for the foreground tab when the browser is put to the // background (and also for any tab when it is put to the background of the // browser). The browser can only be killed by the system when it is in the // background, so saving the Geolocation permission state now ensures that // is maintained when the browser is killed. - ChromeClient* chromeClient = GET_NATIVE_VIEW(env, obj)->mainFrame()->page()->chrome()->client(); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + ChromeClient* chromeClient = viewImpl->mainFrame()->page()->chrome()->client(); ChromeClientAndroid* chromeClientAndroid = static_cast<ChromeClientAndroid*>(chromeClient); chromeClientAndroid->storeGeolocationPermissions(); - Frame* mainFrame = GET_NATIVE_VIEW(env, obj)->mainFrame(); + Frame* mainFrame = viewImpl->mainFrame(); for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) { Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation(); if (geolocation) geolocation->suspend(); } + if (mainFrame) + mainFrame->settings()->setMinDOMTimerInterval(BACKGROUND_TIMER_INTERVAL); - GET_NATIVE_VIEW(env, obj)->deviceMotionAndOrientationManager()->maybeSuspendClients(); + viewImpl->deviceMotionAndOrientationManager()->maybeSuspendClients(); ANPEvent event; SkANP::InitEvent(&event, kLifecycle_ANPEventType); event.data.lifecycle.action = kPause_ANPLifecycleAction; - GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event); + viewImpl->sendPluginEvent(event); - GET_NATIVE_VIEW(env, obj)->setIsPaused(true); + viewImpl->setIsPaused(true); } -static void Resume(JNIEnv* env, jobject obj) +static void Resume(JNIEnv* env, jobject obj, jint nativeClass) { - Frame* mainFrame = GET_NATIVE_VIEW(env, obj)->mainFrame(); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + Frame* mainFrame = viewImpl->mainFrame(); for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) { Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation(); if (geolocation) geolocation->resume(); } + if (mainFrame) + mainFrame->settings()->setMinDOMTimerInterval(FOREGROUND_TIMER_INTERVAL); - GET_NATIVE_VIEW(env, obj)->deviceMotionAndOrientationManager()->maybeResumeClients(); + viewImpl->deviceMotionAndOrientationManager()->maybeResumeClients(); ANPEvent event; SkANP::InitEvent(&event, kLifecycle_ANPEventType); event.data.lifecycle.action = kResume_ANPLifecycleAction; - GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event); + viewImpl->sendPluginEvent(event); - GET_NATIVE_VIEW(env, obj)->setIsPaused(false); + viewImpl->setIsPaused(false); } -static void FreeMemory(JNIEnv* env, jobject obj) +static void FreeMemory(JNIEnv* env, jobject obj, jint nativeClass) { ANPEvent event; SkANP::InitEvent(&event, kLifecycle_ANPEventType); event.data.lifecycle.action = kFreeMemory_ANPLifecycleAction; - GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event); + reinterpret_cast<WebViewCore*>(nativeClass)->sendPluginEvent(event); } -static void ProvideVisitedHistory(JNIEnv *env, jobject obj, jobject hist) +static void ProvideVisitedHistory(JNIEnv* env, jobject obj, jint nativeClass, + jobject hist) { - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + ALOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); jobjectArray array = static_cast<jobjectArray>(hist); @@ -4545,78 +4871,38 @@ static void ProvideVisitedHistory(JNIEnv *env, jobject obj, jobject hist) } } -static void PluginSurfaceReady(JNIEnv* env, jobject obj) +static void PluginSurfaceReady(JNIEnv* env, jobject obj, jint nativeClass) { - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); if (viewImpl) viewImpl->sendPluginSurfaceReady(); } // Notification from the UI thread that the plugin's full-screen surface has been discarded -static void FullScreenPluginHidden(JNIEnv* env, jobject obj, jint npp) +static void FullScreenPluginHidden(JNIEnv* env, jobject obj, jint nativeClass, + jint npp) { - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); PluginWidgetAndroid* plugin = viewImpl->getPluginWidget((NPP)npp); if (plugin) plugin->exitFullScreen(false); } -static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj) -{ - int L, T, R, B; - GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B); - return WebCore::IntRect(L, T, R - L, B - T); -} - -static bool ValidNodeAndBounds(JNIEnv *env, jobject obj, int frame, int node, - jobject rect) -{ - IntRect nativeRect = jrect_to_webrect(env, rect); - return GET_NATIVE_VIEW(env, obj)->validNodeAndBounds( - reinterpret_cast<Frame*>(frame), - reinterpret_cast<Node*>(node), nativeRect); -} - -static jobject GetTouchHighlightRects(JNIEnv* env, jobject obj, jint x, jint y, jint slop) +static jobject HitTest(JNIEnv* env, jobject obj, jint nativeClass, jint x, + jint y, jint slop, jboolean doMoveMouse) { - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); if (!viewImpl) return 0; - Vector<IntRect> rects = viewImpl->getTouchHighlightRects(x, y, slop); - if (rects.isEmpty()) - return 0; - - jclass arrayClass = env->FindClass("java/util/ArrayList"); - LOG_ASSERT(arrayClass, "Could not find java/util/ArrayList"); - jmethodID init = env->GetMethodID(arrayClass, "<init>", "(I)V"); - LOG_ASSERT(init, "Could not find constructor for ArrayList"); - jobject array = env->NewObject(arrayClass, init, rects.size()); - LOG_ASSERT(array, "Could not create a new ArrayList"); - jmethodID add = env->GetMethodID(arrayClass, "add", "(Ljava/lang/Object;)Z"); - LOG_ASSERT(add, "Could not find add method on ArrayList"); - jclass rectClass = env->FindClass("android/graphics/Rect"); - LOG_ASSERT(rectClass, "Could not find android/graphics/Rect"); - jmethodID rectinit = env->GetMethodID(rectClass, "<init>", "(IIII)V"); - LOG_ASSERT(rectinit, "Could not find init method on Rect"); - - for (size_t i = 0; i < rects.size(); i++) { - jobject rect = env->NewObject(rectClass, rectinit, rects[i].x(), - rects[i].y(), rects[i].maxX(), rects[i].maxY()); - if (rect) { - env->CallBooleanMethod(array, add, rect); - env->DeleteLocalRef(rect); - } - } - - env->DeleteLocalRef(rectClass); - env->DeleteLocalRef(arrayClass); - return array; + AndroidHitTestResult result = viewImpl->hitTestAtPoint(x, y, slop, doMoveMouse); + return result.createJavaObject(env); } -static void AutoFillForm(JNIEnv* env, jobject obj, jint queryId) +static void AutoFillForm(JNIEnv* env, jobject obj, jint nativeClass, + jint queryId) { #if ENABLE(WEB_AUTOFILL) - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); if (!viewImpl) return; @@ -4629,19 +4915,87 @@ static void AutoFillForm(JNIEnv* env, jobject obj, jint queryId) #endif } -static void CloseIdleConnections(JNIEnv* env, jobject obj) +static void CloseIdleConnections(JNIEnv* env, jobject obj, jint nativeClass) { -#if USE(CHROME_NETWORK_STACK) WebCache::get(true)->closeIdleConnections(); WebCache::get(false)->closeIdleConnections(); -#endif } -static void ScrollRenderLayer(JNIEnv* env, jobject obj, jint layer, jobject jRect) +static void nativeCertTrustChanged(JNIEnv *env, jobject obj) +{ + WebCache::get(true)->certTrustChanged(); + WebCache::get(false)->certTrustChanged(); +} + +static void ScrollRenderLayer(JNIEnv* env, jobject obj, jint nativeClass, + jint layer, jobject jRect) { SkRect rect; GraphicsJNI::jrect_to_rect(env, jRect, &rect); - GET_NATIVE_VIEW(env, obj)->scrollRenderLayer(layer, rect); + reinterpret_cast<WebViewCore*>(nativeClass)->scrollRenderLayer(layer, rect); +} + +static void DeleteText(JNIEnv* env, jobject obj, jint nativeClass, + jint startX, jint startY, jint endX, jint endY) +{ + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + viewImpl->deleteText(startX, startY, endX, endY); +} + +static void InsertText(JNIEnv* env, jobject obj, jint nativeClass, + jstring text) +{ + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + WTF::String wtfText = jstringToWtfString(env, text); + viewImpl->insertText(wtfText); +} + +static jobject GetText(JNIEnv* env, jobject obj, jint nativeClass, + jint startX, jint startY, jint endX, jint endY) +{ + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + WTF::String text = viewImpl->getText(startX, startY, endX, endY); + return text.isEmpty() ? 0 : wtfStringToJstring(env, text); +} + +static void SelectText(JNIEnv* env, jobject obj, jint nativeClass, + jint startX, jint startY, jint endX, jint endY) +{ + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + viewImpl->selectText(startX, startY, endX, endY); +} + +static void ClearSelection(JNIEnv* env, jobject obj, jint nativeClass) +{ + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + viewImpl->focusedFrame()->selection()->clear(); +} + +static bool SelectWordAt(JNIEnv* env, jobject obj, jint nativeClass, jint x, jint y) +{ + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + return viewImpl->selectWordAt(x, y); +} + +static void SelectAll(JNIEnv* env, jobject obj, jint nativeClass) +{ + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + viewImpl->focusedFrame()->selection()->selectAll(); +} + +static int FindAll(JNIEnv* env, jobject obj, jint nativeClass, + jstring text) +{ + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + WTF::String wtfText = jstringToWtfString(env, text); + return viewImpl->findTextOnPage(wtfText); +} + +static int FindNext(JNIEnv* env, jobject obj, jint nativeClass, + jboolean forward) +{ + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + return viewImpl->findNextOnPage(forward); } // ---------------------------------------------------------------------------- @@ -4650,164 +5004,159 @@ static void ScrollRenderLayer(JNIEnv* env, jobject obj, jint layer, jobject jRec * JNI registration. */ static JNINativeMethod gJavaWebViewCoreMethods[] = { - { "nativeClearContent", "()V", + { "nativeClearContent", "(I)V", (void*) ClearContent }, - { "nativeFocusBoundsChanged", "()Z", + { "nativeFocusBoundsChanged", "(I)Z", (void*) FocusBoundsChanged } , - { "nativeKey", "(IIIZZZZ)Z", + { "nativeKey", "(IIIIZZZZ)Z", (void*) Key }, - { "nativeClick", "(IIZ)V", - (void*) Click }, - { "nativeContentInvalidateAll", "()V", + { "nativeContentInvalidateAll", "(I)V", (void*) ContentInvalidateAll }, - { "nativeSendListBoxChoices", "([ZI)V", + { "nativeSendListBoxChoices", "(I[ZI)V", (void*) SendListBoxChoices }, - { "nativeSendListBoxChoice", "(I)V", + { "nativeSendListBoxChoice", "(II)V", (void*) SendListBoxChoice }, - { "nativeSetSize", "(IIIFIIIIZ)V", + { "nativeSetSize", "(IIIIFIIIIZ)V", (void*) SetSize }, { "nativeSetScrollOffset", "(IZII)V", (void*) SetScrollOffset }, - { "nativeSetGlobalBounds", "(IIII)V", + { "nativeSetGlobalBounds", "(IIIII)V", (void*) SetGlobalBounds }, - { "nativeSetSelection", "(II)V", + { "nativeSetSelection", "(III)V", (void*) SetSelection } , - { "nativeModifySelection", "(II)Ljava/lang/String;", + { "nativeModifySelection", "(III)Ljava/lang/String;", (void*) ModifySelection }, - { "nativeDeleteSelection", "(III)V", + { "nativeDeleteSelection", "(IIII)V", (void*) DeleteSelection } , - { "nativeReplaceTextfieldText", "(IILjava/lang/String;III)V", + { "nativeReplaceTextfieldText", "(IIILjava/lang/String;III)V", (void*) ReplaceTextfieldText } , - { "nativeMoveFocus", "(II)V", - (void*) MoveFocus }, { "nativeMoveMouse", "(III)V", (void*) MoveMouse }, - { "nativeMoveMouseIfLatest", "(IIII)V", - (void*) MoveMouseIfLatest }, - { "passToJs", "(ILjava/lang/String;IIZZZZ)V", + { "passToJs", "(IILjava/lang/String;IIZZZZ)V", (void*) PassToJs }, - { "nativeScrollFocusedTextInput", "(FI)V", + { "nativeScrollFocusedTextInput", "(IFILandroid/graphics/Rect;)V", (void*) ScrollFocusedTextInput }, - { "nativeSetFocusControllerActive", "(Z)V", + { "nativeSetFocusControllerActive", "(IZ)V", (void*) SetFocusControllerActive }, { "nativeSaveDocumentState", "(I)V", (void*) SaveDocumentState }, { "nativeFindAddress", "(Ljava/lang/String;Z)Ljava/lang/String;", (void*) FindAddress }, - { "nativeHandleTouchEvent", "(I[I[I[IIII)Z", - (void*) HandleTouchEvent }, - { "nativeTouchUp", "(IIIII)V", - (void*) TouchUp }, - { "nativeRetrieveHref", "(II)Ljava/lang/String;", + { "nativeHandleTouchEvent", "(II[I[I[IIII)I", + (void*) HandleTouchEvent }, + { "nativeMouseClick", "(I)Z", + (void*) MouseClick }, + { "nativeRetrieveHref", "(III)Ljava/lang/String;", (void*) RetrieveHref }, - { "nativeRetrieveAnchorText", "(II)Ljava/lang/String;", + { "nativeRetrieveAnchorText", "(III)Ljava/lang/String;", (void*) RetrieveAnchorText }, - { "nativeRetrieveImageSource", "(II)Ljava/lang/String;", + { "nativeRetrieveImageSource", "(III)Ljava/lang/String;", (void*) RetrieveImageSource }, - { "nativeStopPaintingCaret", "()V", - (void*) StopPaintingCaret }, - { "nativeUpdateFrameCache", "()V", - (void*) UpdateFrameCache }, - { "nativeGetContentMinPrefWidth", "()I", + { "nativeGetContentMinPrefWidth", "(I)I", (void*) GetContentMinPrefWidth }, - { "nativeUpdateLayers", "(II)Z", - (void*) UpdateLayers }, { "nativeNotifyAnimationStarted", "(I)V", (void*) NotifyAnimationStarted }, - { "nativeRecordContent", "(Landroid/graphics/Region;Landroid/graphics/Point;)I", + { "nativeRecordContent", "(ILandroid/graphics/Point;)I", (void*) RecordContent }, - { "setViewportSettingsFromNative", "()V", + { "setViewportSettingsFromNative", "(I)V", (void*) SetViewportSettingsFromNative }, - { "nativeSplitContent", "(I)V", - (void*) SplitContent }, - { "nativeSetBackgroundColor", "(I)V", + { "nativeSetBackgroundColor", "(II)V", (void*) SetBackgroundColor }, - { "nativeRegisterURLSchemeAsLocal", "(Ljava/lang/String;)V", + { "nativeRegisterURLSchemeAsLocal", "(ILjava/lang/String;)V", (void*) RegisterURLSchemeAsLocal }, - { "nativeDumpDomTree", "(Z)V", + { "nativeDumpDomTree", "(IZ)V", (void*) DumpDomTree }, - { "nativeDumpRenderTree", "(Z)V", + { "nativeDumpRenderTree", "(IZ)V", (void*) DumpRenderTree }, - { "nativeDumpNavTree", "()V", - (void*) DumpNavTree }, - { "nativeDumpV8Counters", "()V", - (void*) DumpV8Counters }, - { "nativeSetNewStorageLimit", "(J)V", + { "nativeSetNewStorageLimit", "(IJ)V", (void*) SetNewStorageLimit }, - { "nativeGeolocationPermissionsProvide", "(Ljava/lang/String;ZZ)V", + { "nativeGeolocationPermissionsProvide", "(ILjava/lang/String;ZZ)V", (void*) GeolocationPermissionsProvide }, - { "nativeSetIsPaused", "(Z)V", (void*) SetIsPaused }, - { "nativePause", "()V", (void*) Pause }, - { "nativeResume", "()V", (void*) Resume }, - { "nativeFreeMemory", "()V", (void*) FreeMemory }, - { "nativeSetJsFlags", "(Ljava/lang/String;)V", (void*) SetJsFlags }, - { "nativeRequestLabel", "(II)Ljava/lang/String;", + { "nativeSetIsPaused", "(IZ)V", (void*) SetIsPaused }, + { "nativePause", "(I)V", (void*) Pause }, + { "nativeResume", "(I)V", (void*) Resume }, + { "nativeFreeMemory", "(I)V", (void*) FreeMemory }, + { "nativeSetJsFlags", "(ILjava/lang/String;)V", (void*) SetJsFlags }, + { "nativeRequestLabel", "(III)Ljava/lang/String;", (void*) RequestLabel }, - { "nativeRevealSelection", "()V", (void*) RevealSelection }, - { "nativeUpdateFrameCacheIfLoading", "()V", - (void*) UpdateFrameCacheIfLoading }, - { "nativeProvideVisitedHistory", "([Ljava/lang/String;)V", + { "nativeRevealSelection", "(I)V", (void*) RevealSelection }, + { "nativeProvideVisitedHistory", "(I[Ljava/lang/String;)V", (void*) ProvideVisitedHistory }, - { "nativeFullScreenPluginHidden", "(I)V", + { "nativeFullScreenPluginHidden", "(II)V", (void*) FullScreenPluginHidden }, - { "nativePluginSurfaceReady", "()V", + { "nativePluginSurfaceReady", "(I)V", (void*) PluginSurfaceReady }, - { "nativeValidNodeAndBounds", "(IILandroid/graphics/Rect;)Z", - (void*) ValidNodeAndBounds }, - { "nativeGetTouchHighlightRects", "(III)Ljava/util/ArrayList;", - (void*) GetTouchHighlightRects }, - { "nativeAutoFillForm", "(I)V", + { "nativeHitTest", "(IIIIZ)Landroid/webkit/WebViewCore$WebKitHitTest;", + (void*) HitTest }, + { "nativeAutoFillForm", "(II)V", (void*) AutoFillForm }, - { "nativeScrollLayer", "(ILandroid/graphics/Rect;)V", + { "nativeScrollLayer", "(IILandroid/graphics/Rect;)V", (void*) ScrollRenderLayer }, - { "nativeCloseIdleConnections", "()V", + { "nativeCloseIdleConnections", "(I)V", (void*) CloseIdleConnections }, + { "nativeDeleteText", "(IIIII)V", + (void*) DeleteText }, + { "nativeInsertText", "(ILjava/lang/String;)V", + (void*) InsertText }, + { "nativeGetText", "(IIIII)Ljava/lang/String;", + (void*) GetText }, + { "nativeSelectText", "(IIIII)V", + (void*) SelectText }, + { "nativeClearTextSelection", "(I)V", + (void*) ClearSelection }, + { "nativeSelectWordAt", "(III)Z", + (void*) SelectWordAt }, + { "nativeSelectAll", "(I)V", + (void*) SelectAll }, + { "nativeCertTrustChanged","()V", + (void*) nativeCertTrustChanged }, + { "nativeFindAll", "(ILjava/lang/String;)I", + (void*) FindAll }, + { "nativeFindNext", "(IZ)I", + (void*) FindNext }, + { "nativeSetInitialFocus", "(II)V", (void*) SetInitialFocus }, }; int registerWebViewCore(JNIEnv* env) { jclass widget = env->FindClass("android/webkit/WebViewCore"); - LOG_ASSERT(widget, + ALOG_ASSERT(widget, "Unable to find class android/webkit/WebViewCore"); gWebViewCoreFields.m_nativeClass = env->GetFieldID(widget, "mNativeClass", "I"); - LOG_ASSERT(gWebViewCoreFields.m_nativeClass, + ALOG_ASSERT(gWebViewCoreFields.m_nativeClass, "Unable to find android/webkit/WebViewCore.mNativeClass"); gWebViewCoreFields.m_viewportWidth = env->GetFieldID(widget, "mViewportWidth", "I"); - LOG_ASSERT(gWebViewCoreFields.m_viewportWidth, + ALOG_ASSERT(gWebViewCoreFields.m_viewportWidth, "Unable to find android/webkit/WebViewCore.mViewportWidth"); gWebViewCoreFields.m_viewportHeight = env->GetFieldID(widget, "mViewportHeight", "I"); - LOG_ASSERT(gWebViewCoreFields.m_viewportHeight, + ALOG_ASSERT(gWebViewCoreFields.m_viewportHeight, "Unable to find android/webkit/WebViewCore.mViewportHeight"); gWebViewCoreFields.m_viewportInitialScale = env->GetFieldID(widget, "mViewportInitialScale", "I"); - LOG_ASSERT(gWebViewCoreFields.m_viewportInitialScale, + ALOG_ASSERT(gWebViewCoreFields.m_viewportInitialScale, "Unable to find android/webkit/WebViewCore.mViewportInitialScale"); gWebViewCoreFields.m_viewportMinimumScale = env->GetFieldID(widget, "mViewportMinimumScale", "I"); - LOG_ASSERT(gWebViewCoreFields.m_viewportMinimumScale, + ALOG_ASSERT(gWebViewCoreFields.m_viewportMinimumScale, "Unable to find android/webkit/WebViewCore.mViewportMinimumScale"); gWebViewCoreFields.m_viewportMaximumScale = env->GetFieldID(widget, "mViewportMaximumScale", "I"); - LOG_ASSERT(gWebViewCoreFields.m_viewportMaximumScale, + ALOG_ASSERT(gWebViewCoreFields.m_viewportMaximumScale, "Unable to find android/webkit/WebViewCore.mViewportMaximumScale"); gWebViewCoreFields.m_viewportUserScalable = env->GetFieldID(widget, "mViewportUserScalable", "Z"); - LOG_ASSERT(gWebViewCoreFields.m_viewportUserScalable, + ALOG_ASSERT(gWebViewCoreFields.m_viewportUserScalable, "Unable to find android/webkit/WebViewCore.mViewportUserScalable"); gWebViewCoreFields.m_viewportDensityDpi = env->GetFieldID(widget, "mViewportDensityDpi", "I"); - LOG_ASSERT(gWebViewCoreFields.m_viewportDensityDpi, + ALOG_ASSERT(gWebViewCoreFields.m_viewportDensityDpi, "Unable to find android/webkit/WebViewCore.mViewportDensityDpi"); - gWebViewCoreFields.m_webView = env->GetFieldID(widget, - "mWebView", "Landroid/webkit/WebView;"); - LOG_ASSERT(gWebViewCoreFields.m_webView, - "Unable to find android/webkit/WebViewCore.mWebView"); gWebViewCoreFields.m_drawIsPaused = env->GetFieldID(widget, "mDrawIsPaused", "Z"); - LOG_ASSERT(gWebViewCoreFields.m_drawIsPaused, + ALOG_ASSERT(gWebViewCoreFields.m_drawIsPaused, "Unable to find android/webkit/WebViewCore.mDrawIsPaused"); gWebViewCoreFields.m_lowMemoryUsageMb = env->GetFieldID(widget, "mLowMemoryUsageThresholdMb", "I"); gWebViewCoreFields.m_highMemoryUsageMb = env->GetFieldID(widget, "mHighMemoryUsageThresholdMb", "I"); |