diff options
Diffstat (limited to 'WebKit/android/jni/WebViewCore.cpp')
| -rw-r--r-- | WebKit/android/jni/WebViewCore.cpp | 4598 |
1 files changed, 0 insertions, 4598 deletions
diff --git a/WebKit/android/jni/WebViewCore.cpp b/WebKit/android/jni/WebViewCore.cpp deleted file mode 100644 index f2680b5..0000000 --- a/WebKit/android/jni/WebViewCore.cpp +++ /dev/null @@ -1,4598 +0,0 @@ -/* - * Copyright 2006, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#define LOG_TAG "webcoreglue" - -#include "config.h" -#include "WebViewCore.h" - -#include "AccessibilityObject.h" -#include "Attribute.h" -#include "BaseLayerAndroid.h" -#include "CachedNode.h" -#include "CachedRoot.h" -#include "Chrome.h" -#include "ChromeClientAndroid.h" -#include "ChromiumIncludes.h" -#include "ClientRect.h" -#include "ClientRectList.h" -#include "Color.h" -#include "CSSPropertyNames.h" -#include "CSSValueKeywords.h" -#include "DatabaseTracker.h" -#include "Document.h" -#include "DOMWindow.h" -#include "DOMSelection.h" -#include "Element.h" -#include "Editor.h" -#include "EditorClientAndroid.h" -#include "EventHandler.h" -#include "EventNames.h" -#include "ExceptionCode.h" -#include "FocusController.h" -#include "Font.h" -#include "Frame.h" -#include "FrameLoader.h" -#include "FrameLoaderClientAndroid.h" -#include "FrameTree.h" -#include "FrameView.h" -#include "Geolocation.h" -#include "GraphicsContext.h" -#include "GraphicsJNI.h" -#include "HTMLAnchorElement.h" -#include "HTMLAreaElement.h" -#include "HTMLElement.h" -#include "HTMLFormControlElement.h" -#include "HTMLImageElement.h" -#include "HTMLInputElement.h" -#include "HTMLLabelElement.h" -#include "HTMLMapElement.h" -#include "HTMLNames.h" -#include "HTMLOptGroupElement.h" -#include "HTMLOptionElement.h" -#include "HTMLSelectElement.h" -#include "HTMLTextAreaElement.h" -#include "HistoryItem.h" -#include "HitTestRequest.h" -#include "HitTestResult.h" -#include "InlineTextBox.h" -#include "MemoryUsage.h" -#include "NamedNodeMap.h" -#include "Navigator.h" -#include "Node.h" -#include "NodeList.h" -#include "Page.h" -#include "PageGroup.h" -#include "PlatformKeyboardEvent.h" -#include "PlatformString.h" -#include "PluginWidgetAndroid.h" -#include "PluginView.h" -#include "Position.h" -#include "ProgressTracker.h" -#include "Range.h" -#include "RenderBox.h" -#include "RenderInline.h" -#include "RenderLayer.h" -#include "RenderPart.h" -#include "RenderText.h" -#include "RenderTextControl.h" -#include "RenderThemeAndroid.h" -#include "RenderView.h" -#include "ResourceRequest.h" -#include "SchemeRegistry.h" -#include "SelectionController.h" -#include "Settings.h" -#include "SkANP.h" -#include "SkTemplates.h" -#include "SkTDArray.h" -#include "SkTypes.h" -#include "SkCanvas.h" -#include "SkPicture.h" -#include "SkUtils.h" -#include "Text.h" -#include "TypingCommand.h" -#include "WebCoreFrameBridge.h" -#include "WebFrameView.h" -#include "WindowsKeyboardCodes.h" -#include "android_graphics.h" -#include "autofill/WebAutoFill.h" -#include "htmlediting.h" -#include "markup.h" - -#include <JNIHelp.h> -#include <JNIUtility.h> -#include <ui/KeycodeLabels.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 - -#if DEBUG_NAV_UI -#include "SkTime.h" -#endif - -#if ENABLE(TOUCH_EVENTS) // Android -#include "PlatformTouchEvent.h" -#endif - -#ifdef ANDROID_DOM_LOGGING -#include "AndroidLog.h" -#include "RenderTreeAsText.h" -#include <wtf/text/CString.h> - -FILE* gDomTreeFile = 0; -FILE* gRenderTreeFile = 0; -#endif - -#ifdef ANDROID_INSTRUMENT -#include "TimeCounter.h" -#endif - -#if USE(ACCELERATED_COMPOSITING) -#include "GraphicsLayerAndroid.h" -#include "RenderLayerCompositor.h" -#endif - -/* 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 - -//////////////////////////////////////////////////////////////////////////////////////////////// - -namespace android { - -static SkTDArray<WebViewCore*> gInstanceList; - -void WebViewCore::addInstance(WebViewCore* inst) { - *gInstanceList.append() = inst; -} - -void WebViewCore::removeInstance(WebViewCore* inst) { - int index = gInstanceList.find(inst); - LOG_ASSERT(index >= 0, "RemoveInstance inst not found"); - if (index >= 0) { - gInstanceList.removeShuffle(index); - } -} - -bool WebViewCore::isInstance(WebViewCore* inst) { - return gInstanceList.find(inst) >= 0; -} - -jobject WebViewCore::getApplicationContext() { - - // check to see if there is a valid webviewcore object - if (gInstanceList.isEmpty()) - return 0; - - // get the context from the webview - jobject context = gInstanceList[0]->getContext(); - - if (!context) - return 0; - - // get the application context using JNI - JNIEnv* env = JSC::Bindings::getJNIEnv(); - jclass contextClass = env->GetObjectClass(context); - jmethodID appContextMethod = env->GetMethodID(contextClass, "getApplicationContext", "()Landroid/content/Context;"); - env->DeleteLocalRef(contextClass); - jobject result = env->CallObjectMethod(context, appContextMethod); - checkException(env); - return result; -} - - -struct WebViewCoreStaticMethods { - jmethodID m_isSupportedMediaMimeType; -} gWebViewCoreStaticMethods; - -// Check whether a media mimeType is supported in Android media framework. -bool WebViewCore::isSupportedMediaMimeType(const WTF::String& mimeType) { - JNIEnv* env = JSC::Bindings::getJNIEnv(); - jstring jMimeType = wtfStringToJstring(env, mimeType); - jclass webViewCore = env->FindClass("android/webkit/WebViewCore"); - bool val = env->CallStaticBooleanMethod(webViewCore, - gWebViewCoreStaticMethods.m_isSupportedMediaMimeType, jMimeType); - checkException(env); - env->DeleteLocalRef(webViewCore); - env->DeleteLocalRef(jMimeType); - - return val; -} - -// ---------------------------------------------------------------------------- - -#define GET_NATIVE_VIEW(env, obj) ((WebViewCore*)env->GetIntField(obj, gWebViewCoreFields.m_nativeClass)) - -// Field ids for WebViewCore -struct WebViewCoreFields { - jfieldID m_nativeClass; - jfieldID m_viewportWidth; - jfieldID m_viewportHeight; - jfieldID m_viewportInitialScale; - jfieldID m_viewportMinimumScale; - jfieldID m_viewportMaximumScale; - jfieldID m_viewportUserScalable; - jfieldID m_viewportDensityDpi; - jfieldID m_webView; - jfieldID m_drawIsPaused; - jfieldID m_lowMemoryUsageMb; - jfieldID m_highMemoryUsageMb; - jfieldID m_highUsageDeltaMb; -} gWebViewCoreFields; - -// ---------------------------------------------------------------------------- - -struct WebViewCore::JavaGlue { - jweak m_obj; - jmethodID m_scrollTo; - jmethodID m_contentDraw; - jmethodID m_layersDraw; - jmethodID m_requestListBox; - jmethodID m_openFileChooser; - jmethodID m_requestSingleListBox; - jmethodID m_jsAlert; - jmethodID m_jsConfirm; - jmethodID m_jsPrompt; - jmethodID m_jsUnload; - jmethodID m_jsInterrupt; - jmethodID m_didFirstLayout; - jmethodID m_updateViewport; - jmethodID m_sendNotifyProgressFinished; - jmethodID m_sendViewInvalidate; - jmethodID m_updateTextfield; - jmethodID m_updateTextSelection; - jmethodID m_clearTextEntry; - jmethodID m_restoreScale; - jmethodID m_needTouchEvents; - jmethodID m_requestKeyboard; - jmethodID m_requestKeyboardWithSelection; - jmethodID m_exceededDatabaseQuota; - jmethodID m_reachedMaxAppCacheSize; - jmethodID m_populateVisitedLinks; - jmethodID m_geolocationPermissionsShowPrompt; - jmethodID m_geolocationPermissionsHidePrompt; - jmethodID m_getDeviceMotionService; - jmethodID m_getDeviceOrientationService; - jmethodID m_addMessageToConsole; - jmethodID m_formDidBlur; - jmethodID m_getPluginClass; - jmethodID m_showFullScreenPlugin; - jmethodID m_hideFullScreenPlugin; - jmethodID m_createSurface; - jmethodID m_addSurface; - jmethodID m_updateSurface; - 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_setWebTextViewAutoFillable; - jmethodID m_selectAt; - AutoJObject object(JNIEnv* env) { - return getRealObject(env, m_obj); - } -}; - -/* - * WebViewCore Implementation - */ - -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); - return m; -} - -Mutex WebViewCore::gFrameCacheMutex; -Mutex WebViewCore::gButtonMutex; -Mutex WebViewCore::gCursorBoundsMutex; - -WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* mainframe) - : m_pluginInvalTimer(this, &WebViewCore::pluginInvalTimerFired) - , m_deviceMotionAndOrientationManager(this) -{ - m_mainFrame = mainframe; - - m_popupReply = 0; - m_moveGeneration = 0; - m_lastGeneration = 0; - m_touchGeneration = 0; - m_blockTextfieldUpdates = false; - // just initial values. These should be set by client - m_maxXScroll = 320/4; - m_maxYScroll = 240/4; - m_textGeneration = 0; - m_screenWidth = 320; - m_textWrapWidth = 320; - m_scale = 1; -#if ENABLE(TOUCH_EVENTS) - m_forwardingTouchEvents = false; -#endif - m_isPaused = false; - m_screenOnCounter = 0; - m_shouldPaintCaret = true; - - LOG_ASSERT(m_mainFrame, "Uh oh, somehow a frameview was made without an initial frame!"); - - jclass clazz = env->GetObjectClass(javaWebViewCore); - m_javaGlue = new JavaGlue; - 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_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_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_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"); - m_javaGlue->m_geolocationPermissionsShowPrompt = GetJMethod(env, clazz, "geolocationPermissionsShowPrompt", "(Ljava/lang/String;)V"); - m_javaGlue->m_geolocationPermissionsHidePrompt = GetJMethod(env, clazz, "geolocationPermissionsHidePrompt", "()V"); - 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_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;I)V"); - m_javaGlue->m_hideFullScreenPlugin = GetJMethod(env, clazz, "hideFullScreenPlugin", "()V"); - m_javaGlue->m_createSurface = GetJMethod(env, clazz, "createSurface", "(Landroid/view/View;)Landroid/webkit/ViewManager$ChildView;"); - m_javaGlue->m_addSurface = GetJMethod(env, clazz, "addSurface", "(Landroid/view/View;IIII)Landroid/webkit/ViewManager$ChildView;"); - m_javaGlue->m_updateSurface = GetJMethod(env, clazz, "updateSurface", "(Landroid/webkit/ViewManager$ChildView;IIII)V"); - 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"); -#endif - m_javaGlue->m_setWebTextViewAutoFillable = GetJMethod(env, clazz, "setWebTextViewAutoFillable", "(ILjava/lang/String;)V"); - m_javaGlue->m_selectAt = GetJMethod(env, clazz, "selectAt", "(II)V"); - env->DeleteLocalRef(clazz); - - env->SetIntField(javaWebViewCore, gWebViewCoreFields.m_nativeClass, (jint)this); - - m_scrollOffsetX = m_scrollOffsetY = 0; - - PageGroup::setShouldTrackVisitedLinks(true); - - reset(true); - - MemoryUsage::setLowMemoryUsageMb(env->GetIntField(javaWebViewCore, gWebViewCoreFields.m_lowMemoryUsageMb)); - MemoryUsage::setHighMemoryUsageMb(env->GetIntField(javaWebViewCore, gWebViewCoreFields.m_highMemoryUsageMb)); - MemoryUsage::setHighUsageDeltaMb(env->GetIntField(javaWebViewCore, gWebViewCoreFields.m_highUsageDeltaMb)); - - WebViewCore::addInstance(this); - -#if USE(CHROME_NETWORK_STACK) - AndroidNetworkLibraryImpl::InitWithApplicationContext(env, 0); -#endif -} - -WebViewCore::~WebViewCore() -{ - WebViewCore::removeInstance(this); - - // Release the focused view - Release(m_popupReply); - - if (m_javaGlue->m_obj) { - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->DeleteWeakGlobalRef(m_javaGlue->m_obj); - 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)); -} - -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(); -} - -void WebViewCore::reset(bool fromConstructor) -{ - DBG_SET_LOG(""); - if (fromConstructor) { - m_frameCacheKit = 0; - m_navPictureKit = 0; - } else { - gFrameCacheMutex.lock(); - delete m_frameCacheKit; - delete m_navPictureKit; - m_frameCacheKit = 0; - m_navPictureKit = 0; - gFrameCacheMutex.unlock(); - } - - m_lastFocused = 0; - m_blurringNodePointer = 0; - m_lastFocusedBounds = WebCore::IntRect(0,0,0,0); - m_focusBoundsChanged = false; - m_lastFocusedSelStart = 0; - m_lastFocusedSelEnd = 0; - clearContent(); - m_updatedFrameCache = true; - m_frameCacheOutOfDate = true; - m_skipContentDraw = false; - m_findIsUp = false; - m_domtree_version = 0; - m_check_domtree_version = true; - m_progressDone = false; - m_hasCursorBounds = false; - - m_scrollOffsetX = 0; - m_scrollOffsetY = 0; - m_screenWidth = 0; - m_screenHeight = 0; - m_groupForVisitedLinks = 0; - m_currentNodeDomNavigationAxis = 0; -} - -static bool layoutIfNeededRecursive(WebCore::Frame* f) -{ - if (!f) - return true; - - 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(); -} - -WebCore::Node* WebViewCore::currentFocus() -{ - return cacheBuilder().currentFocus(); -} - -void WebViewCore::recordPicture(SkPicture* picture) -{ - // 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__); - - // Copy m_buttons so we can pass it to our graphics context. - gButtonMutex.lock(); - WTF::Vector<Container> buttons(m_buttons); - gButtonMutex.unlock(); - - WebCore::PlatformGraphicsContext pgc(arp.getRecordingCanvas(), &buttons); - WebCore::GraphicsContext gc(&pgc); - view->platformWidget()->draw(&gc, WebCore::IntRect(0, 0, - view->contentsWidth(), view->contentsHeight())); - - gButtonMutex.lock(); - updateButtonList(&buttons); - gButtonMutex.unlock(); -} - -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 there is a pending style recalculation, just return. - if (m_mainFrame->document()->isPendingStyleRecalc()) { - LOGW("recordPictureSet: pending style recalc, ignoring."); - return; - } - if (m_addInval.isEmpty()) { - DBG_SET_LOG("m_addInval.isEmpty()"); - 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(); - int height = view->contentsHeight(); - - // Use the contents width and height as a starting point. - SkIRect contentRect; - contentRect.set(0, 0, width, height); - SkIRect total(contentRect); - - // Traverse all the frames and add their sizes if they are in the visible - // rectangle. - for (WebCore::Frame* frame = m_mainFrame->tree()->traverseNext(); frame; - frame = frame->tree()->traverseNext()) { - // If the frame doesn't have an owner then it is the top frame and the - // view size is the frame size. - WebCore::RenderPart* owner = frame->ownerRenderer(); - if (owner && owner->style()->visibility() == VISIBLE) { - int x = owner->x(); - int y = owner->y(); - - // Traverse the tree up to the parent to find the absolute position - // of this frame. - WebCore::Frame* parent = frame->tree()->parent(); - while (parent) { - WebCore::RenderPart* parentOwner = parent->ownerRenderer(); - if (parentOwner) { - x += parentOwner->x(); - y += parentOwner->y(); - } - parent = parent->tree()->parent(); - } - // Use the owner dimensions so that padding and border are - // included. - int right = x + owner->width(); - int bottom = y + owner->height(); - SkIRect frameRect = {x, y, right, bottom}; - // Ignore a width or height that is smaller than 1. Some iframes - // have small dimensions in order to be hidden. The iframe - // expansion code does not expand in that case so we should ignore - // them here. - if (frameRect.width() > 1 && frameRect.height() > 1 - && SkIRect::Intersects(total, frameRect)) - total.join(x, y, right, bottom); - } - } - - // If the new total is larger than the content, resize the view to include - // all the content. - if (!contentRect.contains(total)) { - // Resize the view to change the overflow clip. - view->resize(total.fRight, total.fBottom); - - // We have to force a layout in order for the clip to change. - m_mainFrame->contentRenderer()->setNeedsLayoutAndPrefWidthsRecalc(); - 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(); - } - - if (cacheBuilder().pictureSetDisabled()) - content->clear(); - - content->checkDimensions(width, height, &m_addInval); - - // The inval region may replace existing pictures. The existing pictures - // may have already been split into pieces. If reuseSubdivided() returns - // true, the split pieces are the last entries in the picture already. They - // are marked as invalid, and are rebuilt by rebuildPictureSet(). - - // If the new region doesn't match a set of split pieces, add it to the end. - if (!content->reuseSubdivided(m_addInval)) { - const SkIRect& inval = m_addInval.getBounds(); - SkPicture* picture = rebuildPicture(inval); - DBG_SET_LOGD("{%d,%d,w=%d,h=%d}", inval.fLeft, - inval.fTop, inval.width(), inval.height()); - content->add(m_addInval, picture, 0, false); - SkSafeUnref(picture); - } - // Remove any pictures already in the set that are obscured by the new one, - // and check to see if any already split pieces need to be redrawn. - if (content->build()) - 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(); - env->CallVoidMethod(m_javaGlue->object(env).get(), - m_javaGlue->m_sendFindAgain); - checkException(env); - } -} - -void WebViewCore::updateButtonList(WTF::Vector<Container>* buttons) -{ - // All the entries in buttons are either updates of previous entries in - // m_buttons or they need to be added to it. - Container* end = buttons->end(); - for (Container* updatedContainer = buttons->begin(); - updatedContainer != end; updatedContainer++) { - bool updated = false; - // Search for a previous entry that references the same node as our new - // data - Container* lastPossibleMatch = m_buttons.end(); - for (Container* possibleMatch = m_buttons.begin(); - possibleMatch != lastPossibleMatch; possibleMatch++) { - if (updatedContainer->matches(possibleMatch->node())) { - // Update our record, and skip to the next one. - possibleMatch->setRect(updatedContainer->rect()); - updated = true; - break; - } - } - if (!updated) { - // This is a brand new button, so append it to m_buttons - m_buttons.append(*updatedContainer); - } - } - size_t i = 0; - // count will decrease each time one is removed, so check count each time. - while (i < m_buttons.size()) { - if (m_buttons[i].canBeRemoved()) { - m_buttons[i] = m_buttons.last(); - m_buttons.removeLast(); - } else { - i++; - } - } -} - -// 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(); -} - -void WebViewCore::clearContent() -{ - DBG_SET_LOG(""); - m_content.clear(); - m_addInval.setEmpty(); - m_rebuildInval.setEmpty(); -} - -bool WebViewCore::focusBoundsChanged() -{ - bool result = m_focusBoundsChanged; - m_focusBoundsChanged = false; - return result; -} - -SkPicture* WebViewCore::rebuildPicture(const SkIRect& inval) -{ - 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(); - - gButtonMutex.lock(); - WTF::Vector<Container> buttons(m_buttons); - gButtonMutex.unlock(); - - WebCore::PlatformGraphicsContext pgc(recordingCanvas, &buttons); - WebCore::GraphicsContext gc(&pgc); - recordingCanvas->translate(-inval.fLeft, -inval.fTop); - recordingCanvas->save(); - view->platformWidget()->draw(&gc, WebCore::IntRect(inval.fLeft, - inval.fTop, inval.width(), inval.height())); - 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); - - gButtonMutex.lock(); - updateButtonList(&buttons); - gButtonMutex.unlock(); - - return picture; -} - -void WebViewCore::rebuildPictureSet(PictureSet* pictureSet) -{ - WebCore::FrameView* view = m_mainFrame->view(); - 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)); - } - pictureSet->validate(__FUNCTION__); -} - -BaseLayerAndroid* WebViewCore::createBaseLayer() -{ - BaseLayerAndroid* base = new BaseLayerAndroid(); - base->setContent(m_content); - - bool layoutSucceeded = layoutIfNeededRecursive(m_mainFrame); - // Layout only fails if called during a layout. - LOG_ASSERT(layoutSucceeded, "Can never be called recursively"); - -#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); - } - } - - // We update the layers - ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(m_mainFrame->page()->chrome()->client()); - GraphicsLayerAndroid* root = static_cast<GraphicsLayerAndroid*>(chromeC->layersSync()); - if (root) { - root->notifyClientAnimationStarted(); - LayerAndroid* copyLayer = new LayerAndroid(*root->contentLayer()); - base->addChild(copyLayer); - copyLayer->unref(); - } -#endif - - return base; -} - -BaseLayerAndroid* WebViewCore::recordContent(SkRegion* region, SkIPoint* point) -{ - DBG_SET_LOG("start"); - 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(); - region->op(m_rebuildInval, SkRegion::kUnion_Op); - 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"); - - return createBaseLayer(); -} - -void WebViewCore::splitContent(PictureSet* content) -{ - bool layoutSucceeded = layoutIfNeededRecursive(m_mainFrame); - LOG_ASSERT(layoutSucceeded, "Can never be called recursively"); - content->split(&m_content); - rebuildPictureSet(&m_content); - content->set(m_content); -} - -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); - - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_scrollTo, - x, y, animate, false); - checkException(env); -} - -void WebViewCore::sendNotifyProgressFinished() -{ - LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_sendNotifyProgressFinished); - checkException(env); -} - -void WebViewCore::viewInvalidate(const WebCore::IntRect& rect) -{ - LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), - m_javaGlue->m_sendViewInvalidate, - rect.x(), rect.y(), rect.right(), rect.bottom()); - checkException(env); -} - -void WebViewCore::contentDraw() -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_contentDraw); - checkException(env); -} - -void WebViewCore::layersDraw() -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).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); - if (!m_skipContentDraw) - contentDraw(); -} - -void WebViewCore::contentInvalidateAll() -{ - WebCore::FrameView* view = m_mainFrame->view(); - contentInvalidate(WebCore::IntRect(0, 0, - view->contentsWidth(), view->contentsHeight())); -} - -void WebViewCore::offInvalidate(const WebCore::IntRect &r) -{ - // FIXME: these invalidates are offscreen, and can be throttled or - // deferred until the area is visible. For now, treat them as - // regular invals so that drawing happens (inefficiently) for now. - 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!"); - - WebCore::FrameLoader* loader = m_mainFrame->loader(); - const WebCore::KURL& url = loader->url(); - if (url.isEmpty()) - return; - LOGV("::WebCore:: didFirstLayout %s", url.string().ascii().data()); - - WebCore::FrameLoadType loadType = loader->loadType(); - - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_didFirstLayout, - loadType == WebCore::FrameLoadTypeStandard - // When redirect with locked history, we would like to reset the - // scale factor. This is important for www.yahoo.com as it is - // redirected to www.yahoo.com/?rs=1 on load. - || loadType == WebCore::FrameLoadTypeRedirectWithLockedBackForwardList); - 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!"); - - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_updateViewport); - checkException(env); -} - -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!"); - - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_restoreScale, scale, textWrapScale); - checkException(env); -} - -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!"); - -#if ENABLE(TOUCH_EVENTS) - if (m_forwardingTouchEvents == need) - return; - - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_needTouchEvents, need); - checkException(env); - - m_forwardingTouchEvents = 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(); - env->CallVoidMethod(m_javaGlue->object(env).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!"); - - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), - m_javaGlue->m_requestKeyboard, showKeyboard); - checkException(env); -} - -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) -{ - 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; - // The visible rect is located within our coordinate space so it - // contains the actual scroll position. Setting the location makes hit - // testing work correctly. - m_mainFrame->view()->platformWidget()->setLocation(m_scrollOffsetX, - m_scrollOffsetY); - if (sendScrollEvent) { - m_mainFrame->eventHandler()->sendScrollEvent(); - - // Only update history position if it's user scrolled. - // Update history item to reflect the new scroll position. - // This also helps save the history information when the browser goes to - // background, so scroll position will be restored if browser gets - // killed while in background. - WebCore::HistoryController* history = m_mainFrame->loader()->history(); - // Because the history item saving could be heavy for large sites and - // scrolling can generate lots of small scroll offset, the following code - // reduces the saving frequency. - static const int MIN_SCROLL_DIFF = 32; - if (history->currentItem()) { - WebCore::IntPoint currentPoint = history->currentItem()->scrollPoint(); - if (std::abs(currentPoint.x() - dx) >= MIN_SCROLL_DIFF || - std::abs(currentPoint.y() - dy) >= MIN_SCROLL_DIFF) { - history->saveScrollPositionAndViewStateToItem(history->currentItem()); - } - } - } - - // 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); -} - -void WebViewCore::setSizeScreenWidthAndScale(int width, int height, - int textWrapWidth, float scale, int screenWidth, int screenHeight, - int anchorX, int anchorY, bool ignoreHeight) -{ - WebCoreViewBridge* window = m_mainFrame->view()->platformWidget(); - int ow = window->width(); - int oh = window->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; - if (scale >= 0) // negative means keep the current scale - m_scale = scale; - m_maxXScroll = screenWidth >> 2; - m_maxYScroll = m_maxXScroll * height / width; - // Don't reflow if the diff is small. - const bool reflow = otw && textWrapWidth && - ((float) abs(otw - textWrapWidth) / textWrapWidth) >= 0.01f; - - // When the screen size change, fixed positioned element should be updated. - // This is supposed to be light weighted operation without a full layout. - if (osh != screenHeight || osw != screenWidth) - m_mainFrame->view()->updatePositionedObjects(); - - 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; - // If the text wrap changed, it is probably zoom change or - // orientation change. Try to keep the anchor at the same place. - if (otw && textWrapWidth && otw != textWrapWidth && - (anchorX != 0 || anchorY != 0)) { - WebCore::HitTestResult 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. - if (bounds.width() == 0) { - 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()); - } - } - } - - // Set the size after finding the old anchor point as - // hitTestResultAtPoint causes a layout. - window->setSize(width, height); - window->setVisibleSize(screenWidth, screenHeight); - if (width != screenWidth) { - m_mainFrame->view()->setUseFixedLayout(true); - m_mainFrame->view()->setFixedLayoutSize(IntSize(width, height)); - } else { - m_mainFrame->view()->setUseFixedLayout(false); - } - r->setNeedsLayoutAndPrefWidthsRecalc(); - m_mainFrame->view()->forceLayout(); - - // scroll to restore current screen center - if (node) { - 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(); - // force left align if width is not changed while height changed. - // the anchorPoint is probably at some white space in the node - // which is affected by text wrap around the screen width. - const bool leftAlign = (otw != textWrapWidth) - && (bounds.width() == newBounds.width()) - && (bounds.height() != newBounds.height()); - const float xPercentInDoc = - leftAlign ? 0.0 : (float) (anchorX - bounds.x()) / bounds.width(); - const float xPercentInView = - leftAlign ? 0.0 : (float) (anchorX - m_scrollOffsetX) / osw; - const float yPercentInDoc = (float) (anchorY - bounds.y()) / bounds.height(); - const float yPercentInView = (float) (anchorY - m_scrollOffsetY) / osh; - showRect(newBounds.x(), newBounds.y(), newBounds.width(), - newBounds.height(), view->contentsWidth(), - view->contentsHeight(), - xPercentInDoc, xPercentInView, - yPercentInDoc, yPercentInView); - } - } - } - } else { - window->setSize(width, height); - window->setVisibleSize(screenWidth, screenHeight); - m_mainFrame->view()->resize(width, height); - if (width != screenWidth) { - m_mainFrame->view()->setUseFixedLayout(true); - m_mainFrame->view()->setFixedLayoutSize(IntSize(width, height)); - } else { - m_mainFrame->view()->setUseFixedLayout(false); - } - } - - // update the currently visible screen as perceived by the plugin - sendPluginVisibleScreen(); -} - -void WebViewCore::dumpDomTree(bool useFile) -{ -#ifdef ANDROID_DOM_LOGGING - if (useFile) - gDomTreeFile = fopen(DOM_TREE_LOG_FILE, "w"); - m_mainFrame->document()->showTreeForThis(); - if (gDomTreeFile) { - fclose(gDomTreeFile); - gDomTreeFile = 0; - } -#endif -} - -void WebViewCore::dumpRenderTree(bool useFile) -{ -#ifdef ANDROID_DOM_LOGGING - WTF::CString renderDump = WebCore::externalRepresentation(m_mainFrame).utf8(); - const char* data = renderDump.data(); - if (useFile) { - gRenderTreeFile = fopen(RENDER_TREE_LOG_FILE, "w"); - DUMP_RENDER_LOGD("%s", data); - fclose(gRenderTreeFile); - gRenderTreeFile = 0; - } else { - // adb log can only output 1024 characters, so write out line by line. - // exclude '\n' as adb log adds it for each output. - int length = renderDump.length(); - for (int i = 0, last = 0; i < length; i++) { - if (data[i] == '\n') { - if (i != last) - DUMP_RENDER_LOGD("%.*s", (i - last), &(data[last])); - last = i + 1; - } - } - } -#endif -} - -void WebViewCore::dumpNavTree() -{ -#if DUMP_NAV_CACHE - cacheBuilder().mDebug.print(); -#endif -} - -HTMLElement* WebViewCore::retrieveElement(int x, int y, - const QualifiedName& tagName) -{ - HitTestResult hitTestResult = m_mainFrame->eventHandler() - ->hitTestResultAtPoint(IntPoint(x, y), false, false, - DontHitTestScrollbars, HitTestRequest::Active | HitTestRequest::ReadOnly, - IntSize(1, 1)); - if (!hitTestResult.innerNode() || !hitTestResult.innerNode()->inDocument()) { - LOGE("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"); - return 0; - } - Node* node = hitTestResult.innerNode(); - Node* element = node; - while (element && (!element->isElementNode() - || !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); -} - -HTMLAnchorElement* WebViewCore::retrieveAnchorElement(int x, int y) -{ - return static_cast<HTMLAnchorElement*> - (retrieveElement(x, y, HTMLNames::aTag)); -} - -HTMLImageElement* WebViewCore::retrieveImageElement(int x, int y) -{ - return static_cast<HTMLImageElement*> - (retrieveElement(x, y, HTMLNames::imgTag)); -} - -WTF::String WebViewCore::retrieveHref(int x, int y) -{ - WebCore::HTMLAnchorElement* anchor = retrieveAnchorElement(x, y); - return anchor ? anchor->href() : WTF::String(); -} - -WTF::String WebViewCore::retrieveAnchorText(int x, int y) -{ - WebCore::HTMLAnchorElement* anchor = retrieveAnchorElement(x, y); - return anchor ? anchor->text() : WTF::String(); -} - -WTF::String WebViewCore::retrieveImageSource(int x, int y) -{ - HTMLImageElement* image = retrieveImageElement(x, y); - return image ? image->src().string() : WTF::String(); -} - -WTF::String WebViewCore::requestLabel(WebCore::Frame* frame, - WebCore::Node* node) -{ - if (node && CacheBuilder::validNode(m_mainFrame, frame, node)) { - RefPtr<WebCore::NodeList> list = node->document()->getElementsByTagName("label"); - unsigned length = list->length(); - for (unsigned i = 0; i < length; i++) { - WebCore::HTMLLabelElement* label = static_cast<WebCore::HTMLLabelElement*>( - list->item(i)); - if (label->control() == node) { - Node* node = label; - String result; - while ((node = node->traverseNextNode(label))) { - if (node->isTextNode()) { - Text* textNode = static_cast<Text*>(node); - result += textNode->dataImpl(); - } - } - return result; - } - } - } - return WTF::String(); -} - -static bool isContentEditable(const WebCore::Node* node) -{ - if (!node) return false; - return node->document()->frame()->selection()->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; - WebCore::RenderObject* renderer = node->renderer(); - return renderer && (renderer->isTextField() || renderer->isTextArea()); -} - -void WebViewCore::revealSelection() -{ - WebCore::Node* focus = currentFocus(); - if (!focus) - return; - if (!isTextInput(focus)) - return; - WebCore::Frame* focusedFrame = focus->document()->frame(); - if (!focusedFrame->page()->focusController()->isActive()) - return; - 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; -#if DEBUG_NAV_UI - m_now = SkTime::GetMSecs(); -#endif - 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; - IntRect mBounds; -}; - -// get the bounding box of the Node -static IntRect getAbsoluteBoundingBox(Node* node) { - IntRect rect; - RenderObject* render = node->renderer(); - if (render->isRenderInline()) - rect = toRenderInline(render)->linesVisualOverflowBoundingBox(); - else if (render->isBox()) - rect = toRenderBox(render)->visualOverflowRect(); - else if (render->isText()) - rect = toRenderText(render)->linesBoundingBox(); - else - LOGE("getAbsoluteBoundingBox failed for node %p, name %s", node, render->renderName()); - FloatPoint absPos = render->localToAbsolute(); - rect.move(absPos.x(), absPos.y()); - return rect; -} - -// get the highlight rectangles for the touch point (x, y) with the slop -Vector<IntRect> WebViewCore::getTouchHighlightRects(int x, int y, int slop) -{ - Vector<IntRect> rects; - m_mousePos = IntPoint(x - m_scrollOffsetX, y - m_scrollOffsetY); - HitTestResult hitTestResult = m_mainFrame->eventHandler()->hitTestResultAtPoint(IntPoint(x, y), - false, false, DontHitTestScrollbars, HitTestRequest::Active | HitTestRequest::ReadOnly, IntSize(slop, slop)); - if (!hitTestResult.innerNode() || !hitTestResult.innerNode()->inDocument()) { - LOGE("Should not happen: no in document Node found"); - return rects; - } - const ListHashSet<RefPtr<Node> >& list = hitTestResult.rectBasedTestResult(); - if (list.isEmpty()) { - LOGE("Should not happen: no rect-based-test nodes found"); - return rects; - } - Frame* frame = hitTestResult.innerNode()->document()->frame(); - Vector<TouchNodeData> nodeDataList; - 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? - // if the node is not in the same frame as the innerNode, skip it - if (it->get()->document()->frame() != frame) - continue; - // traverse up the tree to find the first node that needs highlight - bool found = false; - Node* eventNode = it->get(); - while (eventNode) { - RenderObject* render = eventNode->renderer(); - if (render->isBody() || render->isRenderView()) - break; - if (eventNode->supportsFocus() - || eventNode->hasEventListeners(eventNames().clickEvent) - || eventNode->hasEventListeners(eventNames().mousedownEvent) - || eventNode->hasEventListeners(eventNames().mouseupEvent)) { - found = true; - break; - } - // the nodes in the rectBasedTestResult() are ordered based on z-index during hit testing. - // so do not search for the eventNode across explicit z-index border. - // TODO: this is a hard one to call. z-index is quite complicated as its value only - // matters when you compare two RenderLayer in the same hierarchy level. e.g. in - // the following example, "b" is on the top as its z level is the highest. even "c" - // has 100 as z-index, it is still below "d" as its parent has the same z-index as - // "d" and logically before "d". Of course "a" is the lowest in the z level. - // - // z-index:auto "a" - // z-index:2 "b" - // z-index:1 - // z-index:100 "c" - // z-index:1 "d" - // - // If the fat point touches everyone, the order in the list should be "b", "d", "c" - // and "a". When we search for the event node for "b", we really don't want "a" as - // in the z-order it is behind everything else. - if (!render->style()->hasAutoZIndex()) - break; - eventNode = eventNode->parentNode(); - } - // didn't find any eventNode, skip it - if (!found) - continue; - // first quick check whether it is a duplicated node before computing bounding box - 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) { - found = false; - break; - } - } - if (!found) - continue; - // next check whether the node is fully covered by or fully covering another node. - found = false; - IntRect rect = getAbsoluteBoundingBox(eventNode); - if (rect.isEmpty()) { - // if the node's bounds is empty and it is not a ContainerNode, skip it. - if (!eventNode->isContainerNode()) - continue; - // if the node's children are all positioned objects, its bounds can be empty. - // Walk through the children to find the bounding box. - Node* child = static_cast<const ContainerNode*>(eventNode)->firstChild(); - while (child) { - IntRect childrect; - if (child->renderer()) - childrect = getAbsoluteBoundingBox(child); - if (!childrect.isEmpty()) { - rect.unite(childrect); - child = child->traverseNextSibling(eventNode); - } else - child = child->traverseNextNode(eventNode); - } - } - for (int i = nodeDataList.size() - 1; i >= 0; i--) { - TouchNodeData n = nodeDataList.at(i); - // the new node is enclosing an existing node, skip it - if (rect.contains(n.mBounds)) { - found = true; - break; - } - // the new node is fully inside an existing node, remove the existing node - if (n.mBounds.contains(rect)) - nodeDataList.remove(i); - } - if (!found) { - TouchNodeData newNode; - newNode.mNode = eventNode; - newNode.mBounds = rect; - nodeDataList.append(newNode); - } - } - if (!nodeDataList.size()) - return rects; - // finally select the node with the largest overlap with the fat point - TouchNodeData final; - final.mNode = 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; - Vector<TouchNodeData>::const_iterator nlast = nodeDataList.end(); - for (Vector<TouchNodeData>::const_iterator n = nodeDataList.begin(); n != nlast; ++n) { - IntRect rect = n->mBounds; - rect.intersect(testRect); - int a = rect.width() * rect.height(); - if (a > area) { - 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.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].right()) { - 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].bottom()) { - if (y - rects[i].bottom() + 1 < distance) { - newx = x; - newy = rects[i].bottom() - 1; - distance = y - rects[i].bottom() + 1; - } - } - } else if (y >= rects[i].y() && y < rects[i].bottom()) { - 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].right()) { - if (x - rects[i].right() + 1 < distance) { - newx = rects[i].right() - 1; - newy = y; - distance = x - rects[i].right() + 1; - } - } - } - } - 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; - } - } - 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); - } - } - return rects; -} - -/////////////////////////////////////////////////////////////////////////////// - -void WebViewCore::addPlugin(PluginWidgetAndroid* w) -{ -// SkDebugf("----------- addPlugin %p", w); - /* The plugin must be appended to the end of the array. This ensures that if - the plugin is added while iterating through the array (e.g. sendEvent(...)) - that the iteration process is not corrupted. - */ - *m_plugins.append() = w; -} - -void WebViewCore::removePlugin(PluginWidgetAndroid* w) -{ -// SkDebugf("----------- removePlugin %p", w); - int index = m_plugins.find(w); - if (index < 0) { - SkDebugf("--------------- pluginwindow not found! %p\n", w); - } else { - m_plugins.removeShuffle(index); - } -} - -bool WebViewCore::isPlugin(PluginWidgetAndroid* w) const -{ - return m_plugins.find(w) >= 0; -} - -void WebViewCore::invalPlugin(PluginWidgetAndroid* w) -{ - const double PLUGIN_INVAL_DELAY = 1.0 / 60; - - if (!m_pluginInvalTimer.isActive()) { - m_pluginInvalTimer.startOneShot(PLUGIN_INVAL_DELAY); - } -} - -void WebViewCore::drawPlugins() -{ - SkRegion inval; // accumualte what needs to be redrawn - PluginWidgetAndroid** iter = m_plugins.begin(); - PluginWidgetAndroid** stop = m_plugins.end(); - - for (; iter < stop; ++iter) { - PluginWidgetAndroid* w = *iter; - SkIRect dirty; - if (w->isDirty(&dirty)) { - w->draw(); - inval.op(dirty, SkRegion::kUnion_Op); - } - } - - if (!inval.isEmpty()) { - // inval.getBounds() is our rectangle - const SkIRect& bounds = inval.getBounds(); - WebCore::IntRect r(bounds.fLeft, bounds.fTop, - bounds.width(), bounds.height()); - this->viewInvalidate(r); - } -} - -void WebViewCore::notifyPluginsOnFrameLoad(const Frame* frame) { - // if frame is the parent then notify all plugins - if (!frame->tree()->parent()) { - // trigger an event notifying the plugins that the page has loaded - ANPEvent event; - SkANP::InitEvent(&event, kLifecycle_ANPEventType); - event.data.lifecycle.action = kOnLoad_ANPLifecycleAction; - sendPluginEvent(event); - // trigger the on/off screen notification if the page was reloaded - sendPluginVisibleScreen(); - } - // else if frame's parent has completed - else if (!frame->tree()->parent()->loader()->isLoading()) { - // send to all plugins who have this frame in their heirarchy - PluginWidgetAndroid** iter = m_plugins.begin(); - PluginWidgetAndroid** stop = m_plugins.end(); - for (; iter < stop; ++iter) { - Frame* currentFrame = (*iter)->pluginView()->parentFrame(); - while (currentFrame) { - if (frame == currentFrame) { - ANPEvent event; - SkANP::InitEvent(&event, kLifecycle_ANPEventType); - event.data.lifecycle.action = kOnLoad_ANPLifecycleAction; - (*iter)->sendEvent(event); - - // trigger the on/off screen notification if the page was reloaded - ANPRectI visibleRect; - getVisibleScreen(visibleRect); - (*iter)->setVisibleScreen(visibleRect, m_scale); - - break; - } - currentFrame = currentFrame->tree()->parent(); - } - } - } -} - -void WebViewCore::getVisibleScreen(ANPRectI& visibleRect) -{ - visibleRect.left = m_scrollOffsetX; - visibleRect.top = m_scrollOffsetY; - visibleRect.right = m_scrollOffsetX + m_screenWidth; - visibleRect.bottom = m_scrollOffsetY + m_screenHeight; -} - -void WebViewCore::sendPluginVisibleScreen() -{ - /* We may want to cache the previous values and only send the notification - to the plugin in the event that one of the values has changed. - */ - - ANPRectI visibleRect; - getVisibleScreen(visibleRect); - - PluginWidgetAndroid** iter = m_plugins.begin(); - PluginWidgetAndroid** stop = m_plugins.end(); - for (; iter < stop; ++iter) { - (*iter)->setVisibleScreen(visibleRect, m_scale); - } -} - -void WebViewCore::sendPluginEvent(const ANPEvent& evt) -{ - /* The list of plugins may be manipulated as we iterate through the list. - This implementation allows for the addition of new plugins during an - iteration, but may fail if a plugin is removed. Currently, there are not - any use cases where a plugin is deleted while processing this loop, but - if it does occur we will have to use an alternate data structure and/or - iteration mechanism. - */ - for (int x = 0; x < m_plugins.count(); x++) { - m_plugins[x]->sendEvent(evt); - } -} - -PluginWidgetAndroid* WebViewCore::getPluginWidget(NPP npp) -{ - PluginWidgetAndroid** iter = m_plugins.begin(); - PluginWidgetAndroid** stop = m_plugins.end(); - for (; iter < stop; ++iter) { - if ((*iter)->pluginView()->instance() == npp) { - return (*iter); - } - } - return 0; -} - -static PluginView* nodeIsPlugin(Node* node) { - RenderObject* renderer = node->renderer(); - if (renderer && renderer->isWidget()) { - Widget* widget = static_cast<RenderWidget*>(renderer)->widget(); - if (widget && widget->isPluginView()) - return static_cast<PluginView*>(widget); - } - 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) -{ - 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); - // 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(); -} - -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; - } - // 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); - client->setUiGeneratedSelectionChange(false); - WebCore::Frame* focusedFrame = focus->document()->frame(); - bool isPasswordField = false; - if (focus->isElementNode()) { - WebCore::Element* element = static_cast<WebCore::Element*>(focus); - if (WebCore::InputElement* inputElement = WebCore::toInputElement(element)) - isPasswordField = static_cast<WebCore::HTMLInputElement*>(inputElement)->isPasswordField(); - } - // For password fields, this is done in the UI side via - // bringPointIntoView, since the UI does the drawing. - if (renderer->isTextArea() || !isPasswordField) - revealSelection(); -} - -String WebViewCore::modifySelection(const int direction, const int axis) -{ - DOMSelection* selection = m_mainFrame->domWindow()->getSelection(); - if (selection->rangeCount() > 1) - selection->removeAllRanges(); - switch (axis) { - case AXIS_CHARACTER: - case AXIS_WORD: - case AXIS_SENTENCE: - return modifySelectionTextNavigationAxis(selection, direction, axis); - case AXIS_HEADING: - case AXIS_SIBLING: - case AXIS_PARENT_FIRST_CHILD: - case AXIS_DOCUMENT: - return modifySelectionDomNavigationAxis(selection, direction, axis); - default: - LOGE("Invalid navigation axis: %d", axis); - return String(); - } -} - -void WebViewCore::scrollNodeIntoView(Frame* frame, Node* node) -{ - if (!frame || !node) - return; - - Element* elementNode = 0; - - // If not an Element, find a visible predecessor - // Element to scroll into view. - if (!node->isElementNode()) { - HTMLElement* body = frame->document()->body(); - do { - if (!node || node == body) - return; - node = node->parentNode(); - } while (!node->isElementNode() && !isVisible(node)); - } - - elementNode = static_cast<Element*>(node); - elementNode->scrollIntoViewIfNeeded(true); -} - -String WebViewCore::modifySelectionTextNavigationAxis(DOMSelection* selection, int direction, int axis) -{ - Node* body = m_mainFrame->document()->body(); - - ExceptionCode ec = 0; - String markup; - - // initialize the selection if necessary - if (selection->rangeCount() == 0) { - if (m_currentNodeDomNavigationAxis - && CacheBuilder::validNode(m_mainFrame, - m_mainFrame, m_currentNodeDomNavigationAxis)) { - PassRefPtr<Range> rangeRef = - selection->frame()->document()->createRange(); - rangeRef->selectNode(m_currentNodeDomNavigationAxis, ec); - m_currentNodeDomNavigationAxis = 0; - if (ec) - return String(); - 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); - } - if (ec) - return String(); - } - - // collapse the selection - if (direction == DIRECTION_FORWARD) - selection->collapseToEnd(ec); - else - selection->collapseToStart(ec); - if (ec) - return String(); - - // Make sure the anchor node is a text node since we are generating - // the markup of the selection which includes the anchor, the focus, - // and any crossed nodes. Forcing the condition that the selection - // starts and ends on text nodes guarantees symmetric selection markup. - // Also this way the text content, rather its container, is highlighted. - Node* anchorNode = selection->anchorNode(); - if (anchorNode->isElementNode()) { - // Collapsed selection while moving forward points to the - // next unvisited node and while moving backward to the - // last visited node. - if (direction == DIRECTION_FORWARD) - advanceAnchorNode(selection, direction, markup, false, ec); - else - advanceAnchorNode(selection, direction, markup, true, ec); - if (ec) - return String(); - if (!markup.isEmpty()) - return markup; - } - - // If the selection is at the end of a non white space text move - // it to the next visible text node with non white space content. - // This is a workaround for the selection getting stuck. - anchorNode = selection->anchorNode(); - if (anchorNode->isTextNode()) { - if (direction == DIRECTION_FORWARD) { - String suffix = anchorNode->textContent().substring( - selection->anchorOffset(), caretMaxOffset(anchorNode)); - // If at the end of non white space text we advance the - // anchor node to either an input element or non empty text. - if (suffix.stripWhiteSpace().isEmpty()) { - advanceAnchorNode(selection, direction, markup, true, ec); - } - } else { - String prefix = anchorNode->textContent().substring(0, - selection->anchorOffset()); - // If at the end of non white space text we advance the - // anchor node to either an input element or non empty text. - if (prefix.stripWhiteSpace().isEmpty()) { - advanceAnchorNode(selection, direction, markup, true, ec); - } - } - if (ec) - return String(); - if (!markup.isEmpty()) - return markup; - } - - // extend the selection - String directionStr; - if (direction == DIRECTION_FORWARD) - directionStr = "forward"; - else - directionStr = "backward"; - - String axisStr; - if (axis == AXIS_CHARACTER) - axisStr = "character"; - else if (axis == AXIS_WORD) - axisStr = "word"; - else - axisStr = "sentence"; - - selection->modify("extend", directionStr, axisStr); - - // Make sure the focus node is a text node in order to have the - // selection generate symmetric markup because the latter - // includes all nodes crossed by the selection. Also this way - // the text content, rather its container, is highlighted. - Node* focusNode = selection->focusNode(); - if (focusNode->isElementNode()) { - focusNode = getImplicitBoundaryNode(selection->focusNode(), - selection->focusOffset(), direction); - if (!focusNode) - return String(); - if (direction == DIRECTION_FORWARD) { - focusNode = focusNode->traversePreviousSiblingPostOrder(body); - if (focusNode && !isContentTextNode(focusNode)) { - Node* textNode = traverseNextContentTextNode(focusNode, - anchorNode, DIRECTION_BACKWARD); - if (textNode) - anchorNode = textNode; - } - if (focusNode && isContentTextNode(focusNode)) { - selection->extend(focusNode, caretMaxOffset(focusNode), ec); - if (ec) - return String(); - } - } else { - focusNode = focusNode->traverseNextSibling(); - if (focusNode && !isContentTextNode(focusNode)) { - Node* textNode = traverseNextContentTextNode(focusNode, - anchorNode, DIRECTION_FORWARD); - if (textNode) - anchorNode = textNode; - } - if (anchorNode && isContentTextNode(anchorNode)) { - selection->extend(focusNode, 0, ec); - if (ec) - return String(); - } - } - } - - // Enforce that the selection does not cross anchor boundaries. This is - // a workaround for the asymmetric behavior of WebKit while crossing - // anchors. - anchorNode = getImplicitBoundaryNode(selection->anchorNode(), - selection->anchorOffset(), direction); - focusNode = getImplicitBoundaryNode(selection->focusNode(), - selection->focusOffset(), direction); - if (anchorNode && focusNode && anchorNode != focusNode) { - Node* inputControl = getIntermediaryInputElement(anchorNode, focusNode, - direction); - if (inputControl) { - if (direction == DIRECTION_FORWARD) { - if (isDescendantOf(inputControl, anchorNode)) { - focusNode = inputControl; - } else { - focusNode = inputControl->traversePreviousSiblingPostOrder( - body); - if (!focusNode) - focusNode = inputControl; - } - // We prefer a text node contained in the input element. - if (!isContentTextNode(focusNode)) { - Node* textNode = traverseNextContentTextNode(focusNode, - anchorNode, DIRECTION_BACKWARD); - if (textNode) - focusNode = textNode; - } - // If we found text in the input select it. - // Otherwise, select the input element itself. - if (isContentTextNode(focusNode)) { - selection->extend(focusNode, caretMaxOffset(focusNode), ec); - } else if (anchorNode != focusNode) { - // Note that the focusNode always has parent and that - // the offset can be one more that the index of the last - // element - this is how WebKit selects such elements. - selection->extend(focusNode->parentNode(), - focusNode->nodeIndex() + 1, ec); - } - if (ec) - return String(); - } else { - if (isDescendantOf(inputControl, anchorNode)) { - focusNode = inputControl; - } else { - focusNode = inputControl->traverseNextSibling(); - if (!focusNode) - focusNode = inputControl; - } - // We prefer a text node contained in the input element. - if (!isContentTextNode(focusNode)) { - Node* textNode = traverseNextContentTextNode(focusNode, - anchorNode, DIRECTION_FORWARD); - if (textNode) - focusNode = textNode; - } - // If we found text in the input select it. - // Otherwise, select the input element itself. - if (isContentTextNode(focusNode)) { - selection->extend(focusNode, caretMinOffset(focusNode), ec); - } else if (anchorNode != focusNode) { - // Note that the focusNode always has parent and that - // the offset can be one more that the index of the last - // element - this is how WebKit selects such elements. - selection->extend(focusNode->parentNode(), - focusNode->nodeIndex() + 1, ec); - } - if (ec) - return String(); - } - } - } - - // make sure the selection is visible - if (direction == DIRECTION_FORWARD) - scrollNodeIntoView(m_mainFrame, selection->focusNode()); - else - scrollNodeIntoView(m_mainFrame, selection->anchorNode()); - - // format markup for the visible content - PassRefPtr<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()); - - return markup; -} - -Node* WebViewCore::getImplicitBoundaryNode(Node* node, unsigned offset, int direction) -{ - if (node->offsetInCharacters()) - return node; - if (!node->hasChildNodes()) - return node; - if (offset < node->childNodeCount()) - return node->childNode(offset); - else - if (direction == DIRECTION_FORWARD) - return node->traverseNextSibling(); - else - return node->traversePreviousNodePostOrder( - node->document()->body()); -} - -Node* WebViewCore::getNextAnchorNode(Node* anchorNode, bool ignoreFirstNode, int direction) -{ - Node* body = 0; - Node* currentNode = 0; - if (direction == DIRECTION_FORWARD) { - if (ignoreFirstNode) - currentNode = anchorNode->traverseNextNode(body); - else - currentNode = anchorNode; - } else { - body = anchorNode->document()->body(); - if (ignoreFirstNode) - currentNode = anchorNode->traversePreviousSiblingPostOrder(body); - else - currentNode = anchorNode; - } - while (currentNode) { - if (isContentTextNode(currentNode) - || isContentInputElement(currentNode)) - return currentNode; - if (direction == DIRECTION_FORWARD) - currentNode = currentNode->traverseNextNode(); - else - currentNode = currentNode->traversePreviousNodePostOrder(body); - } - return 0; -} - -void WebViewCore::advanceAnchorNode(DOMSelection* selection, int direction, - String& markup, bool ignoreFirstNode, ExceptionCode& ec) -{ - Node* anchorNode = getImplicitBoundaryNode(selection->anchorNode(), - selection->anchorOffset(), direction); - if (!anchorNode) { - ec = NOT_FOUND_ERR; - return; - } - // If the anchor offset is invalid i.e. the anchor node has no - // child with that index getImplicitAnchorNode returns the next - // logical node in the current direction. In such a case our - // position in the DOM tree was has already been advanced, - // therefore we there is no need to do that again. - if (selection->anchorNode()->isElementNode()) { - unsigned anchorOffset = selection->anchorOffset(); - unsigned childNodeCount = selection->anchorNode()->childNodeCount(); - if (anchorOffset >= childNodeCount) - ignoreFirstNode = false; - } - // Find the next anchor node given our position in the DOM and - // whether we want the current node to be considered as well. - Node* nextAnchorNode = getNextAnchorNode(anchorNode, ignoreFirstNode, - direction); - if (!nextAnchorNode) { - ec = NOT_FOUND_ERR; - return; - } - if (nextAnchorNode->isElementNode()) { - // If this is an input element tell the WebView thread - // to set the cursor to that control. - if (isContentInputElement(nextAnchorNode)) { - IntRect bounds = nextAnchorNode->getRect(); - selectAt(bounds.center().x(), bounds.center().y()); - } - Node* textNode = 0; - // Treat the text content of links as any other text but - // for the rest input elements select the control itself. - if (nextAnchorNode->hasTagName(WebCore::HTMLNames::aTag)) - textNode = traverseNextContentTextNode(nextAnchorNode, - nextAnchorNode, direction); - // We prefer to select the text content of the link if such, - // otherwise just select the element itself. - if (textNode) { - nextAnchorNode = textNode; - } else { - if (direction == DIRECTION_FORWARD) { - selection->setBaseAndExtent(nextAnchorNode, - caretMinOffset(nextAnchorNode), nextAnchorNode, - caretMaxOffset(nextAnchorNode), ec); - } else { - selection->setBaseAndExtent(nextAnchorNode, - caretMaxOffset(nextAnchorNode), nextAnchorNode, - caretMinOffset(nextAnchorNode), ec); - } - if (!ec) - markup = formatMarkup(selection); - // make sure the selection is visible - scrollNodeIntoView(selection->frame(), nextAnchorNode); - return; - } - } - if (direction == DIRECTION_FORWARD) - selection->setPosition(nextAnchorNode, - caretMinOffset(nextAnchorNode), ec); - else - selection->setPosition(nextAnchorNode, - caretMaxOffset(nextAnchorNode), ec); -} - -bool WebViewCore::isContentInputElement(Node* node) -{ - return (isVisible(node) - && (node->hasTagName(WebCore::HTMLNames::selectTag) - || node->hasTagName(WebCore::HTMLNames::aTag) - || node->hasTagName(WebCore::HTMLNames::inputTag) - || node->hasTagName(WebCore::HTMLNames::buttonTag))); -} - -bool WebViewCore::isContentTextNode(Node* node) -{ - if (!node || !node->isTextNode()) - return false; - Text* textNode = static_cast<Text*>(node); - return (isVisible(textNode) && textNode->length() > 0 - && !textNode->containsOnlyWhitespace()); -} - -Text* WebViewCore::traverseNextContentTextNode(Node* fromNode, Node* toNode, int direction) -{ - Node* currentNode = fromNode; - do { - if (direction == DIRECTION_FORWARD) - currentNode = currentNode->traverseNextNode(toNode); - else - currentNode = currentNode->traversePreviousNodePostOrder(toNode); - } while (currentNode && !isContentTextNode(currentNode)); - return static_cast<Text*>(currentNode); -} - -Node* WebViewCore::getIntermediaryInputElement(Node* fromNode, Node* toNode, int direction) -{ - if (fromNode == toNode) - return 0; - if (direction == DIRECTION_FORWARD) { - Node* currentNode = fromNode; - while (currentNode && currentNode != toNode) { - if (isContentInputElement(currentNode)) - return currentNode; - currentNode = currentNode->traverseNextNodePostOrder(); - } - currentNode = fromNode; - while (currentNode && currentNode != toNode) { - if (isContentInputElement(currentNode)) - return currentNode; - currentNode = currentNode->traverseNextNode(); - } - } else { - Node* currentNode = fromNode->traversePreviousNode(); - while (currentNode && currentNode != toNode) { - if (isContentInputElement(currentNode)) - return currentNode; - currentNode = currentNode->traversePreviousNode(); - } - currentNode = fromNode->traversePreviousNodePostOrder(); - while (currentNode && currentNode != toNode) { - if (isContentInputElement(currentNode)) - return currentNode; - currentNode = currentNode->traversePreviousNodePostOrder(); - } - } - return 0; -} - -bool WebViewCore::isDescendantOf(Node* parent, Node* node) -{ - Node* currentNode = node; - while (currentNode) { - if (currentNode == parent) { - return true; - } - currentNode = currentNode->parentNode(); - } - return false; -} - -String WebViewCore::modifySelectionDomNavigationAxis(DOMSelection* selection, int direction, int axis) -{ - HTMLElement* body = m_mainFrame->document()->body(); - if (!m_currentNodeDomNavigationAxis && selection->focusNode()) { - m_currentNodeDomNavigationAxis = selection->focusNode(); - selection->empty(); - if (m_currentNodeDomNavigationAxis->isTextNode()) - m_currentNodeDomNavigationAxis = - m_currentNodeDomNavigationAxis->parentNode(); - } - if (!m_currentNodeDomNavigationAxis) - m_currentNodeDomNavigationAxis = currentFocus(); - if (!m_currentNodeDomNavigationAxis - || !CacheBuilder::validNode(m_mainFrame, m_mainFrame, - m_currentNodeDomNavigationAxis)) - m_currentNodeDomNavigationAxis = body; - Node* currentNode = m_currentNodeDomNavigationAxis; - if (axis == AXIS_HEADING) { - if (currentNode == body && direction == DIRECTION_BACKWARD) - currentNode = currentNode->lastDescendant(); - do { - if (direction == DIRECTION_FORWARD) - currentNode = currentNode->traverseNextNode(body); - else - currentNode = currentNode->traversePreviousNode(body); - } while (currentNode && (currentNode->isTextNode() - || !isVisible(currentNode) || !isHeading(currentNode))); - } else if (axis == AXIS_PARENT_FIRST_CHILD) { - if (direction == DIRECTION_FORWARD) { - currentNode = currentNode->firstChild(); - while (currentNode && (currentNode->isTextNode() - || !isVisible(currentNode))) - currentNode = currentNode->nextSibling(); - } else { - do { - if (currentNode == body) - return String(); - currentNode = currentNode->parentNode(); - } while (currentNode && (currentNode->isTextNode() - || !isVisible(currentNode))); - } - } else if (axis == AXIS_SIBLING) { - do { - if (direction == DIRECTION_FORWARD) - currentNode = currentNode->nextSibling(); - else { - if (currentNode == body) - return String(); - currentNode = currentNode->previousSibling(); - } - } while (currentNode && (currentNode->isTextNode() - || !isVisible(currentNode))); - } else if (axis == AXIS_DOCUMENT) { - currentNode = body; - if (direction == DIRECTION_FORWARD) - currentNode = currentNode->lastDescendant(); - } else { - LOGE("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()); - return selectionString; - } - return String(); -} - -bool WebViewCore::isHeading(Node* node) -{ - if (node->hasTagName(WebCore::HTMLNames::h1Tag) - || node->hasTagName(WebCore::HTMLNames::h2Tag) - || node->hasTagName(WebCore::HTMLNames::h3Tag) - || node->hasTagName(WebCore::HTMLNames::h4Tag) - || node->hasTagName(WebCore::HTMLNames::h5Tag) - || node->hasTagName(WebCore::HTMLNames::h6Tag)) { - return true; - } - - if (node->isElementNode()) { - Element* element = static_cast<Element*>(node); - String roleAttribute = - element->getAttribute(WebCore::HTMLNames::roleAttr).string(); - if (equalIgnoringCase(roleAttribute, "heading")) - return true; - } - - return false; -} - -bool WebViewCore::isVisible(Node* node) -{ - // start off an element - Element* element = 0; - if (node->isElementNode()) - element = static_cast<Element*>(node); - else - element = node->parentElement(); - // check renderer - if (!element->renderer()) { - return false; - } - // check size - if (element->offsetHeight() == 0 || element->offsetWidth() == 0) { - return false; - } - // check style - Node* body = m_mainFrame->document()->body(); - Node* currentNode = element; - while (currentNode && currentNode != body) { - RenderStyle* style = currentNode->computedStyle(); - if (style && - (style->display() == NONE || style->visibility() == HIDDEN)) { - return false; - } - currentNode = currentNode->parentNode(); - } - return true; -} - -String WebViewCore::formatMarkup(DOMSelection* selection) -{ - ExceptionCode ec = 0; - String markup = String(); - PassRefPtr<Range> wholeRange = selection->getRangeAt(0, ec); - if (ec) - return String(); - if (!wholeRange->startContainer() || !wholeRange->startContainer()) - return String(); - // Since formatted markup contains invisible nodes it - // is created from the concatenation of the visible fragments. - Node* firstNode = wholeRange->firstNode(); - Node* pastLastNode = wholeRange->pastLastNode(); - Node* currentNode = firstNode; - PassRefPtr<Range> currentRange; - - while (currentNode != pastLastNode) { - Node* nextNode = currentNode->traverseNextNode(); - if (!isVisible(currentNode)) { - if (currentRange) { - markup = markup + currentRange->toHTML().utf8().data(); - currentRange = 0; - } - } else { - if (!currentRange) { - currentRange = selection->frame()->document()->createRange(); - if (ec) - break; - if (currentNode == firstNode) { - currentRange->setStart(wholeRange->startContainer(), - wholeRange->startOffset(), ec); - if (ec) - break; - } else { - currentRange->setStart(currentNode->parentNode(), - currentNode->nodeIndex(), ec); - if (ec) - break; - } - } - if (nextNode == pastLastNode) { - currentRange->setEnd(wholeRange->endContainer(), - wholeRange->endOffset(), ec); - if (ec) - break; - markup = markup + currentRange->toHTML().utf8().data(); - } else { - if (currentNode->offsetInCharacters()) - currentRange->setEnd(currentNode, - currentNode->maxCharacterOffset(), ec); - else - currentRange->setEnd(currentNode->parentNode(), - currentNode->nodeIndex() + 1, ec); - if (ec) - break; - } - } - currentNode = nextNode; - } - return markup.stripWhiteSpace(); -} - -void WebViewCore::selectAt(int x, int y) -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_selectAt, - x, y); - checkException(env); -} - -void WebViewCore::deleteSelection(int start, int end, int textGeneration) -{ - setSelection(start, end); - if (start == end) - return; - WebCore::Node* focus = currentFocus(); - if (!focus) - return; - // Prevent our editor client from passing a message to change the - // selection. - EditorClientAndroid* client = static_cast<EditorClientAndroid*>( - m_mainFrame->editor()->client()); - client->setUiGeneratedSelectionChange(true); - PlatformKeyboardEvent down(AKEYCODE_DEL, 0, 0, true, false, false, false); - PlatformKeyboardEvent up(AKEYCODE_DEL, 0, 0, false, false, false, false); - key(down); - key(up); - client->setUiGeneratedSelectionChange(false); - m_textGeneration = textGeneration; - m_shouldPaintCaret = true; -} - -void WebViewCore::replaceTextfieldText(int oldStart, - int oldEnd, const WTF::String& replace, int start, int end, - int textGeneration) -{ - WebCore::Node* focus = currentFocus(); - if (!focus) - return; - setSelection(oldStart, oldEnd); - // Prevent our editor client from passing a message to change the - // selection. - EditorClientAndroid* client = static_cast<EditorClientAndroid*>( - m_mainFrame->editor()->client()); - client->setUiGeneratedSelectionChange(true); - WebCore::TypingCommand::insertText(focus->document(), replace, - false); - 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, - const PlatformKeyboardEvent& event) -{ - 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; - } - // Block text field updates during a key press. - m_blockTextfieldUpdates = true; - // Also prevent our editor client from passing a message to change the - // selection. - EditorClientAndroid* client = static_cast<EditorClientAndroid*>( - m_mainFrame->editor()->client()); - client->setUiGeneratedSelectionChange(true); - key(event); - client->setUiGeneratedSelectionChange(false); - m_blockTextfieldUpdates = false; - m_textGeneration = generation; - WebCore::RenderTextControl* renderText = - static_cast<WebCore::RenderTextControl*>(renderer); - WTF::String test = renderText->text(); - 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::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; - } - 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); -} - -void WebViewCore::setFocusControllerActive(bool active) -{ - m_mainFrame->page()->focusController()->setActive(active); -} - -void WebViewCore::saveDocumentState(WebCore::Frame* frame) -{ - if (!CacheBuilder::validNode(m_mainFrame, frame, 0)) - frame = m_mainFrame; - WebCore::HistoryItem *item = frame->loader()->history()->currentItem(); - - // item can be null when there is no offical URL for the current page. This happens - // when the content is loaded using with WebCoreFrameBridge::LoadData() and there - // is no failing URL (common case is when content is loaded using data: scheme) - if (item) { - item->setDocumentState(frame->document()->formElementsState()); - } -} - -// Create an array of java Strings. -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"); - jobjectArray array = env->NewObjectArray(count, stringClass, 0); - LOG_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]); - env->SetObjectArrayElement(array, i, newString); - env->DeleteLocalRef(newString); - checkException(env); - } - env->DeleteLocalRef(stringClass); - return array; -} - -void WebViewCore::openFileChooser(PassRefPtr<WebCore::FileChooser> chooser) { - if (!chooser) - return; - JNIEnv* env = JSC::Bindings::getJNIEnv(); - - WTF::String acceptType = chooser->acceptTypes(); - jstring jAcceptType = wtfStringToJstring(env, acceptType, true); - jstring jName = (jstring) env->CallObjectMethod( - m_javaGlue->object(env).get(), m_javaGlue->m_openFileChooser, jAcceptType); - checkException(env); - env->DeleteLocalRef(jAcceptType); - - const UChar* string = static_cast<const UChar*>(env->GetStringChars(jName, NULL)); - - if (!string) - return; - - WTF::String webcoreString = jstringToWtfString(env, jName); - env->ReleaseStringChars(jName, string); - - if (webcoreString.length()) - chooser->chooseFile(webcoreString); -} - -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) -{ - // If m_popupReply is not null, then we already have a list showing. - if (m_popupReply != 0) - return; - - LOG_ASSERT(m_javaGlue->m_obj, "No java widget associated with this view!"); - - // Create an array of java Strings for the drop down. - JNIEnv* env = JSC::Bindings::getJNIEnv(); - jobjectArray labelArray = makeLabelArray(env, labels, count); - - // Create an array determining whether each item is enabled. - jintArray enabledArray = env->NewIntArray(enabledCount); - checkException(env); - jint* ptrArray = env->GetIntArrayElements(enabledArray, 0); - checkException(env); - for (size_t i = 0; i < enabledCount; i++) { - ptrArray[i] = enabled[i]; - } - env->ReleaseIntArrayElements(enabledArray, ptrArray, 0); - checkException(env); - - if (multiple) { - // Pass up an array representing which items are selected. - jintArray selectedArray = env->NewIntArray(selectedCountOrSelection); - checkException(env); - jint* selArray = env->GetIntArrayElements(selectedArray, 0); - checkException(env); - for (size_t i = 0; i < selectedCountOrSelection; i++) { - selArray[i] = selected[i]; - } - env->ReleaseIntArrayElements(selectedArray, selArray, 0); - - env->CallVoidMethod(m_javaGlue->object(env).get(), - m_javaGlue->m_requestListBox, labelArray, enabledArray, - selectedArray); - env->DeleteLocalRef(selectedArray); - } else { - // Pass up the single selection. - env->CallVoidMethod(m_javaGlue->object(env).get(), - m_javaGlue->m_requestSingleListBox, labelArray, enabledArray, - selectedCountOrSelection); - } - - env->DeleteLocalRef(labelArray); - env->DeleteLocalRef(enabledArray); - checkException(env); - - Retain(reply); - m_popupReply = reply; -} - -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(); - bool handled = eventHandler->keyEvent(event); - 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 - // return false so that the key will be sent back to our navigation - // system. - handled |= frame->selection()->selection() != old; - } - return handled; - } else { - eventHandler = m_mainFrame->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); - } -} - -#if USE(ACCELERATED_COMPOSITING) -GraphicsLayerAndroid* WebViewCore::graphicsRootLayer() const -{ - RenderView* contentRenderer = m_mainFrame->contentRenderer(); - if (!contentRenderer) - return 0; - return static_cast<GraphicsLayerAndroid*>( - contentRenderer->compositor()->rootPlatformLayer()); -} -#endif - -bool WebViewCore::handleTouchEvent(int action, Vector<int>& ids, Vector<IntPoint>& points, int actionIndex, int metaState) -{ - bool preventDefault = false; - -#if USE(ACCELERATED_COMPOSITING) - GraphicsLayerAndroid* rootLayer = graphicsRootLayer(); - if (rootLayer) - rootLayer->pauseDisplay(true); -#endif - -#if ENABLE(TOUCH_EVENTS) // Android - #define MOTION_EVENT_ACTION_POINTER_DOWN 5 - #define MOTION_EVENT_ACTION_POINTER_UP 6 - - WebCore::TouchEventType type = WebCore::TouchStart; - WebCore::PlatformTouchPoint::State defaultTouchState; - Vector<WebCore::PlatformTouchPoint::State> touchStates(points.size()); - - switch (action) { - case 0: // MotionEvent.ACTION_DOWN - type = WebCore::TouchStart; - defaultTouchState = WebCore::PlatformTouchPoint::TouchPressed; - break; - case 1: // MotionEvent.ACTION_UP - type = WebCore::TouchEnd; - defaultTouchState = WebCore::PlatformTouchPoint::TouchReleased; - break; - case 2: // MotionEvent.ACTION_MOVE - type = WebCore::TouchMove; - defaultTouchState = WebCore::PlatformTouchPoint::TouchMoved; - break; - case 3: // MotionEvent.ACTION_CANCEL - type = WebCore::TouchCancel; - defaultTouchState = WebCore::PlatformTouchPoint::TouchCancelled; - break; - case 5: // MotionEvent.ACTION_POINTER_DOWN - type = WebCore::TouchStart; - defaultTouchState = WebCore::PlatformTouchPoint::TouchStationary; - break; - case 6: // MotionEvent.ACTION_POINTER_UP - 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); - return 0; - } - - for (int c = 0; c < static_cast<int>(points.size()); c++) { - points[c].setX(points[c].x() - m_scrollOffsetX); - points[c].setY(points[c].y() - m_scrollOffsetY); - - // Setting the touch state for each point. - // Note: actionIndex will be 0 for all actions that are not ACTION_POINTER_DOWN/UP. - if (action == MOTION_EVENT_ACTION_POINTER_DOWN && c == actionIndex) { - touchStates[c] = WebCore::PlatformTouchPoint::TouchPressed; - } else if (action == MOTION_EVENT_ACTION_POINTER_UP && c == actionIndex) { - touchStates[c] = WebCore::PlatformTouchPoint::TouchReleased; - } else { - touchStates[c] = defaultTouchState; - }; - } - - WebCore::PlatformTouchEvent te(ids, points, type, touchStates, metaState); - preventDefault = m_mainFrame->eventHandler()->handleTouchEvent(te); -#endif - -#if USE(ACCELERATED_COMPOSITING) - if (rootLayer) - rootLayer->pauseDisplay(false); -#endif - return preventDefault; -} - -void WebViewCore::touchUp(int touchGeneration, - WebCore::Frame* frame, WebCore::Node* node, int x, int y) -{ - 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); -} - -// 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"); - const NamedNodeMap* attributes = node->attributes(); - if (!attributes) return false; - size_t length = attributes->length(); - for (size_t i = 0; i < length; i++) { - const Attribute* a = attributes->attributeItem(i); - if (a->localName() == "x-webkit-soft-keyboard" && a->value() == "hidden") - return true; - } - 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; - } - } - 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); - 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(); - } - } - } else if (!fake) { - // There is no focusNode, so the keyboard is not needed. - clearTextEntry(); - } - return handled; -} - -void WebViewCore::popupReply(int index) -{ - if (m_popupReply) { - m_popupReply->replyInt(index); - Release(m_popupReply); - m_popupReply = 0; - } -} - -void WebViewCore::popupReply(const int* array, int count) -{ - if (m_popupReply) { - m_popupReply->replyIntArray(array, count); - Release(m_popupReply); - m_popupReply = 0; - } -} - -void WebViewCore::formDidBlur(const WebCore::Node* node) -{ - // 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); -} - -void WebViewCore::focusNodeChanged(const WebCore::Node* newFocus) -{ - if (isTextInput(newFocus)) - m_shouldPaintCaret = true; - else if (m_blurringNodePointer) { - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), - m_javaGlue->m_formDidBlur, m_blurringNodePointer); - checkException(env); - m_blurringNodePointer = 0; - } -} - -void WebViewCore::addMessageToConsole(const WTF::String& message, unsigned int lineNumber, const WTF::String& sourceID, int msgLevel) { - JNIEnv* env = JSC::Bindings::getJNIEnv(); - jstring jMessageStr = wtfStringToJstring(env, message); - jstring jSourceIDStr = wtfStringToJstring(env, sourceID); - env->CallVoidMethod(m_javaGlue->object(env).get(), - m_javaGlue->m_addMessageToConsole, jMessageStr, lineNumber, - jSourceIDStr, msgLevel); - env->DeleteLocalRef(jMessageStr); - env->DeleteLocalRef(jSourceIDStr); - checkException(env); -} - -void WebViewCore::jsAlert(const WTF::String& url, const WTF::String& text) -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - jstring jInputStr = wtfStringToJstring(env, text); - jstring jUrlStr = wtfStringToJstring(env, url); - env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsAlert, jUrlStr, jInputStr); - env->DeleteLocalRef(jInputStr); - env->DeleteLocalRef(jUrlStr); - checkException(env); -} - -void WebViewCore::exceededDatabaseQuota(const WTF::String& url, const WTF::String& databaseIdentifier, const unsigned long long currentQuota, unsigned long long estimatedSize) -{ -#if ENABLE(DATABASE) - JNIEnv* env = JSC::Bindings::getJNIEnv(); - jstring jDatabaseIdentifierStr = wtfStringToJstring(env, databaseIdentifier); - jstring jUrlStr = wtfStringToJstring(env, url); - env->CallVoidMethod(m_javaGlue->object(env).get(), - m_javaGlue->m_exceededDatabaseQuota, jUrlStr, - jDatabaseIdentifierStr, currentQuota, estimatedSize); - env->DeleteLocalRef(jDatabaseIdentifierStr); - env->DeleteLocalRef(jUrlStr); - checkException(env); -#endif -} - -void WebViewCore::reachedMaxAppCacheSize(const unsigned long long spaceNeeded) -{ -#if ENABLE(OFFLINE_WEB_APPLICATIONS) - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), - m_javaGlue->m_reachedMaxAppCacheSize, spaceNeeded); - checkException(env); -#endif -} - -void WebViewCore::populateVisitedLinks(WebCore::PageGroup* group) -{ - m_groupForVisitedLinks = group; - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_populateVisitedLinks); - checkException(env); -} - -void WebViewCore::geolocationPermissionsShowPrompt(const WTF::String& origin) -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - jstring originString = wtfStringToJstring(env, origin); - env->CallVoidMethod(m_javaGlue->object(env).get(), - m_javaGlue->m_geolocationPermissionsShowPrompt, - originString); - env->DeleteLocalRef(originString); - checkException(env); -} - -void WebViewCore::geolocationPermissionsHidePrompt() -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), - m_javaGlue->m_geolocationPermissionsHidePrompt); - checkException(env); -} - -jobject WebViewCore::getDeviceMotionService() -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - jobject object = env->CallObjectMethod(m_javaGlue->object(env).get(), - m_javaGlue->m_getDeviceMotionService); - checkException(env); - return object; -} - -jobject WebViewCore::getDeviceOrientationService() -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - jobject object = env->CallObjectMethod(m_javaGlue->object(env).get(), - m_javaGlue->m_getDeviceOrientationService); - checkException(env); - return object; -} - -bool WebViewCore::jsConfirm(const WTF::String& url, const WTF::String& text) -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - jstring jInputStr = wtfStringToJstring(env, text); - jstring jUrlStr = wtfStringToJstring(env, url); - jboolean result = env->CallBooleanMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsConfirm, jUrlStr, jInputStr); - env->DeleteLocalRef(jInputStr); - env->DeleteLocalRef(jUrlStr); - checkException(env); - return result; -} - -bool WebViewCore::jsPrompt(const WTF::String& url, const WTF::String& text, const WTF::String& defaultValue, WTF::String& result) -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - jstring jUrlStr = wtfStringToJstring(env, url); - jstring jInputStr = wtfStringToJstring(env, text); - jstring jDefaultStr = wtfStringToJstring(env, defaultValue); - jstring returnVal = static_cast<jstring>(env->CallObjectMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsPrompt, jUrlStr, jInputStr, jDefaultStr)); - env->DeleteLocalRef(jUrlStr); - env->DeleteLocalRef(jInputStr); - env->DeleteLocalRef(jDefaultStr); - checkException(env); - - // If returnVal is null, it means that the user cancelled the dialog. - if (!returnVal) - return false; - - result = jstringToWtfString(env, returnVal); - env->DeleteLocalRef(returnVal); - return true; -} - -bool WebViewCore::jsUnload(const WTF::String& url, const WTF::String& message) -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - jstring jInputStr = wtfStringToJstring(env, message); - jstring jUrlStr = wtfStringToJstring(env, url); - jboolean result = env->CallBooleanMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsUnload, jUrlStr, jInputStr); - env->DeleteLocalRef(jInputStr); - env->DeleteLocalRef(jUrlStr); - checkException(env); - return result; -} - -bool WebViewCore::jsInterrupt() -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - jboolean result = env->CallBooleanMethod(m_javaGlue->object(env).get(), m_javaGlue->m_jsInterrupt); - checkException(env); - return result; -} - -AutoJObject -WebViewCore::getJavaObject() -{ - return m_javaGlue->object(JSC::Bindings::getJNIEnv()); -} - -jobject -WebViewCore::getWebViewJavaObject() -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - return env->GetObjectField(m_javaGlue->object(env).get(), gWebViewCoreFields.m_webView); -} - -void WebViewCore::updateTextSelection() { - WebCore::Node* focusNode = currentFocus(); - if (!focusNode) - return; - RenderObject* renderer = focusNode->renderer(); - if (!renderer || (!renderer->isTextArea() && !renderer->isTextField())) - return; - RenderTextControl* rtc = static_cast<RenderTextControl*>(renderer); - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), - m_javaGlue->m_updateTextSelection, reinterpret_cast<int>(focusNode), - rtc->selectionStart(), rtc->selectionEnd(), m_textGeneration); - checkException(env); -} - -void WebViewCore::updateTextfield(WebCore::Node* ptr, bool changeToPassword, - const WTF::String& text) -{ - if (m_blockTextfieldUpdates) - return; - JNIEnv* env = JSC::Bindings::getJNIEnv(); - if (changeToPassword) { - env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_updateTextfield, - (int) ptr, true, 0, m_textGeneration); - checkException(env); - return; - } - jstring string = wtfStringToJstring(env, text); - env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_updateTextfield, - (int) ptr, false, string, m_textGeneration); - env->DeleteLocalRef(string); - checkException(env); -} - -void WebViewCore::clearTextEntry() -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), - m_javaGlue->m_clearTextEntry); -} - -void WebViewCore::setBackgroundColor(SkColor c) -{ - WebCore::FrameView* view = m_mainFrame->view(); - if (!view) - return; - - // need (int) cast to find the right constructor - WebCore::Color bcolor((int)SkColorGetR(c), (int)SkColorGetG(c), - (int)SkColorGetB(c), (int)SkColorGetA(c)); - view->setBaseBackgroundColor(bcolor); - - // Background color of 0 indicates we want a transparent background - if (c == 0) - view->setTransparent(true); -} - -jclass WebViewCore::getPluginClass(const WTF::String& libName, const char* className) -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - - jstring libString = wtfStringToJstring(env, libName); - jstring classString = env->NewStringUTF(className); - jobject pluginClass = env->CallObjectMethod(m_javaGlue->object(env).get(), - m_javaGlue->m_getPluginClass, - libString, classString); - checkException(env); - - // cleanup unneeded local JNI references - env->DeleteLocalRef(libString); - env->DeleteLocalRef(classString); - - if (pluginClass != NULL) { - return static_cast<jclass>(pluginClass); - } else { - return NULL; - } -} - -void WebViewCore::showFullScreenPlugin(jobject childView, NPP npp) -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - AutoJObject obj = m_javaGlue->object(env); - - env->CallVoidMethod(obj.get(), - m_javaGlue->m_showFullScreenPlugin, childView, (int)npp); - checkException(env); -} - -void WebViewCore::hideFullScreenPlugin() -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), - m_javaGlue->m_hideFullScreenPlugin); - checkException(env); -} - -jobject WebViewCore::createSurface(jobject view) -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - jobject result = env->CallObjectMethod(m_javaGlue->object(env).get(), - m_javaGlue->m_createSurface, view); - checkException(env); - return result; -} - -jobject WebViewCore::addSurface(jobject view, int x, int y, int width, int height) -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - jobject result = env->CallObjectMethod(m_javaGlue->object(env).get(), - m_javaGlue->m_addSurface, - view, x, y, width, height); - checkException(env); - return result; -} - -void WebViewCore::updateSurface(jobject childView, int x, int y, int width, int height) -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), - m_javaGlue->m_updateSurface, childView, - x, y, width, height); - checkException(env); -} - -void WebViewCore::destroySurface(jobject childView) -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_destroySurface, childView); - checkException(env); -} - -jobject WebViewCore::getContext() -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - AutoJObject obj = m_javaGlue->object(env); - - jobject result = env->CallObjectMethod(obj.get(), m_javaGlue->m_getContext); - checkException(env); - return result; -} - -void WebViewCore::keepScreenOn(bool screenOn) { - if ((screenOn && m_screenOnCounter == 0) || (!screenOn && m_screenOnCounter == 1)) { - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_keepScreenOn, screenOn); - checkException(env); - } - - // update the counter - if (screenOn) - m_screenOnCounter++; - else if (m_screenOnCounter > 0) - 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) -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_showRect, - left, top, width, height, contentWidth, contentHeight, - xPercentInDoc, xPercentInView, yPercentInDoc, yPercentInView); - checkException(env); -} - -void WebViewCore::centerFitRect(int x, int y, int width, int height) -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), - m_javaGlue->m_centerFitRect, x, y, width, height); - checkException(env); -} - - -void WebViewCore::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode verticalMode) -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_setScrollbarModes, - horizontalMode, verticalMode); - checkException(env); -} - -void WebViewCore::notifyWebAppCanBeInstalled() -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_setInstallableWebApp); - checkException(env); -} - -#if ENABLE(VIDEO) -void WebViewCore::enterFullscreenForVideoLayer(int layerId, const WTF::String& url) -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - jstring jUrlStr = wtfStringToJstring(env, url); - env->CallVoidMethod(m_javaGlue->object(env).get(), - m_javaGlue->m_enterFullscreenForVideoLayer, layerId, jUrlStr); - checkException(env); -} -#endif - -void WebViewCore::setWebTextViewAutoFillable(int queryId, const string16& previewSummary) -{ -#if ENABLE(WEB_AUTOFILL) - JNIEnv* env = JSC::Bindings::getJNIEnv(); - jstring preview = env->NewString(previewSummary.data(), previewSummary.length()); - env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_setWebTextViewAutoFillable, queryId, preview); - env->DeleteLocalRef(preview); -#endif -} - -bool WebViewCore::drawIsPaused() const -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - return env->GetBooleanField(m_javaGlue->object(env).get(), - gWebViewCoreFields.m_drawIsPaused); -} - -#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 - if (m_webRequestContext) - m_webRequestContext->setUserAgent(WebFrame::getWebFrame(m_mainFrame)->userAgentForURL(0)); // URL not used -} - -void WebViewCore::setWebRequestContextCacheMode(int cacheMode) -{ - m_cacheMode = cacheMode; - // We cannot create a WebRequestContext, because we might not know it this is a private tab or not yet - if (!m_webRequestContext) - return; - - m_webRequestContext->setCacheMode(cacheMode); -} - -WebRequestContext* WebViewCore::webRequestContext() -{ - if (!m_webRequestContext) { - Settings* settings = mainFrame()->settings(); - m_webRequestContext = new WebRequestContext(settings && settings->privateBrowsingEnabled()); - setWebRequestContextUserAgent(); - setWebRequestContextCacheMode(m_cacheMode); - } - return m_webRequestContext.get(); -} -#endif - -void WebViewCore::scrollRenderLayer(int layer, const SkRect& rect) -{ -#if USE(ACCELERATED_COMPOSITING) - GraphicsLayerAndroid* root = graphicsRootLayer(); - if (!root) - return; - - LayerAndroid* layerAndroid = root->platformLayer(); - if (!layerAndroid) - return; - - LayerAndroid* target = layerAndroid->findById(layer); - if (!target) - return; - - RenderLayer* owner = target->owningLayer(); - if (!owner) - return; - - if (owner->stackingContext()) - owner->scrollToOffset(rect.fLeft, rect.fTop, true, false); -#endif -} - -//---------------------------------------------------------------------- -// Native JNI methods -//---------------------------------------------------------------------- -static void RevealSelection(JNIEnv *env, jobject obj) -{ - GET_NATIVE_VIEW(env, obj)->revealSelection(); -} - -static jstring RequestLabel(JNIEnv *env, jobject obj, int framePointer, - int nodePointer) -{ - return wtfStringToJstring(env, GET_NATIVE_VIEW(env, obj)->requestLabel( - (WebCore::Frame*) framePointer, (WebCore::Node*) nodePointer)); -} - -static void ClearContent(JNIEnv *env, jobject obj) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - 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) -{ -#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"); - 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) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "need viewImpl"); - - viewImpl->setScrollOffset(gen, sendScrollEvent, x, y); -} - -static void SetGlobalBounds(JNIEnv *env, jobject obj, 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"); - - 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) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - return GET_NATIVE_VIEW(env, obj)->key(PlatformKeyboardEvent(keyCode, - unichar, repeatCount, isDown, isShift, isAlt, isSym)); -} - -static void Click(JNIEnv *env, jobject obj, int framePtr, int nodePtr, jboolean fake) -{ -#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); -} - -static void ContentInvalidateAll(JNIEnv *env, jobject obj) -{ - GET_NATIVE_VIEW(env, obj)->contentInvalidateAll(); -} - -static void DeleteSelection(JNIEnv *env, jobject obj, jint start, jint end, - jint textGeneration) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - viewImpl->deleteSelection(start, end, textGeneration); -} - -static void SetSelection(JNIEnv *env, jobject obj, jint start, jint end) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - viewImpl->setSelection(start, end); -} - -static jstring ModifySelection(JNIEnv *env, jobject obj, jint direction, jint granularity) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - String selectionString = viewImpl->modifySelection(direction, granularity); - return wtfStringToJstring(env, selectionString); -} - -static void ReplaceTextfieldText(JNIEnv *env, jobject obj, - 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); - WTF::String webcoreString = jstringToWtfString(env, replace); - viewImpl->replaceTextfieldText(oldStart, - oldEnd, webcoreString, start, end, textGeneration); -} - -static void PassToJs(JNIEnv *env, jobject obj, - 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, - PlatformKeyboardEvent(keyCode, keyValue, 0, down, cap, fn, sym)); -} - -static void ScrollFocusedTextInput(JNIEnv *env, jobject obj, jfloat xPercent, - jint y) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - viewImpl->scrollFocusedTextInput(xPercent, y); -} - -static void SetFocusControllerActive(JNIEnv *env, jobject obj, 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"); - viewImpl->setFocusControllerActive(active); -} - -static void SaveDocumentState(JNIEnv *env, jobject obj, jint frame) -{ -#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); -} - -void WebViewCore::addVisitedLink(const UChar* string, int length) -{ - if (m_groupForVisitedLinks) - m_groupForVisitedLinks->addVisitedLink(string, length); -} - -static jint UpdateLayers(JNIEnv *env, jobject obj, jobject region) -{ - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - BaseLayerAndroid* result = viewImpl->createBaseLayer(); - SkRegion* nativeRegion = GraphicsJNI::getNativeRegion(env, region); - if (result) { - SkIRect bounds; - LayerAndroid* root = static_cast<LayerAndroid*>(result->getChild(0)); - if (root) { - root->bounds().roundOut(&bounds); - nativeRegion->setRect(bounds); - } - } - return reinterpret_cast<jint>(result); -} - -static jint RecordContent(JNIEnv *env, jobject obj, jobject region, jobject pt) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - SkRegion* nativeRegion = GraphicsJNI::getNativeRegion(env, region); - SkIPoint nativePt; - BaseLayerAndroid* result = viewImpl->recordContent(nativeRegion, &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) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoice"); - viewImpl->popupReply(choice); -} - -// Set aside a predetermined amount of space in which to place the listbox -// choices, to avoid unnecessary allocations. -// The size here is arbitrary. We want the size to be at least as great as the -// 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) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoices"); - jboolean* ptrArray = env->GetBooleanArrayElements(jArray, 0); - SkAutoSTMalloc<PREPARED_LISTBOX_STORAGE, int> storage(size); - int* array = storage.get(); - int count = 0; - for (int i = 0; i < size; i++) { - if (ptrArray[i]) { - array[count++] = i; - } - } - env->ReleaseBooleanArrayElements(jArray, ptrArray, JNI_ABORT); - viewImpl->popupReply(array, count); -} - -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; - jstring ret = 0; - if (success) - ret = env->NewString(addrChars + start, end - start); - env->ReleaseStringChars(addr, addrChars); - return ret; -} - -static jboolean HandleTouchEvent(JNIEnv *env, jobject obj, 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__); - jint* ptrIdArray = env->GetIntArrayElements(idArray, 0); - jint* ptrXArray = env->GetIntArrayElements(xArray, 0); - jint* ptrYArray = env->GetIntArrayElements(yArray, 0); - Vector<int> ids(count); - Vector<IntPoint> points(count); - for (int c = 0; c < count; c++) { - ids[c] = ptrIdArray[c]; - points[c].setX(ptrXArray[c]); - points[c].setY(ptrYArray[c]); - } - env->ReleaseIntArrayElements(idArray, ptrIdArray, JNI_ABORT); - env->ReleaseIntArrayElements(xArray, ptrXArray, JNI_ABORT); - env->ReleaseIntArrayElements(yArray, ptrYArray, JNI_ABORT); - - 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) -{ -#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); -} - -static jstring RetrieveHref(JNIEnv *env, jobject obj, 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__); - 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) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_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, - 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); -} - -static void UpdateFrameCache(JNIEnv *env, jobject obj) -{ -#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(); -} - -static jint GetContentMinPrefWidth(JNIEnv *env, jobject obj) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); - - WebCore::Frame* frame = viewImpl->mainFrame(); - if (frame) { - WebCore::Document* document = frame->document(); - if (document) { - WebCore::RenderObject* renderer = document->renderer(); - if (renderer && renderer->isRenderView()) { - return renderer->minPreferredLogicalWidth(); - } - } - } - return 0; -} - -static void SetViewportSettingsFromNative(JNIEnv *env, jobject obj) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); - - WebCore::Settings* s = viewImpl->mainFrame()->page()->settings(); - if (!s) - return; - -#ifdef ANDROID_META_SUPPORT - env->SetIntField(obj, gWebViewCoreFields.m_viewportWidth, s->viewportWidth()); - env->SetIntField(obj, gWebViewCoreFields.m_viewportHeight, s->viewportHeight()); - env->SetIntField(obj, gWebViewCoreFields.m_viewportInitialScale, s->viewportInitialScale()); - env->SetIntField(obj, gWebViewCoreFields.m_viewportMinimumScale, s->viewportMinimumScale()); - env->SetIntField(obj, gWebViewCoreFields.m_viewportMaximumScale, s->viewportMaximumScale()); - env->SetBooleanField(obj, gWebViewCoreFields.m_viewportUserScalable, s->viewportUserScalable()); - env->SetIntField(obj, gWebViewCoreFields.m_viewportDensityDpi, s->viewportTargetDensityDpi()); -#endif -} - -static void SetBackgroundColor(JNIEnv *env, jobject obj, 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__); - - viewImpl->setBackgroundColor((SkColor) color); -} - -static void DumpDomTree(JNIEnv *env, jobject obj, jboolean useFile) -{ - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); - - viewImpl->dumpDomTree(useFile); -} - -static void DumpRenderTree(JNIEnv *env, jobject obj, jboolean useFile) -{ - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_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) -{ -#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) { -#if ENABLE(DATABASE) || ENABLE(OFFLINE_WEB_APPLICATIONS) - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - Frame* frame = viewImpl->mainFrame(); - - // The main thread is blocked awaiting this response, so now we can wake it - // up. - ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client()); - chromeC->wakeUpMainThreadWithNewQuota(quota); -#endif -} - -// 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); - 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 - WebCore::SchemeRegistry::registerURLSchemeAsLocal(jstringToWtfString(env, scheme)); -} - -static bool FocusBoundsChanged(JNIEnv* env, jobject obj) -{ - return GET_NATIVE_VIEW(env, obj)->focusBoundsChanged(); -} - -static void Pause(JNIEnv* env, jobject obj) -{ - // 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(); - ChromeClientAndroid* chromeClientAndroid = static_cast<ChromeClientAndroid*>(chromeClient); - chromeClientAndroid->storeGeolocationPermissions(); - - Frame* mainFrame = GET_NATIVE_VIEW(env, obj)->mainFrame(); - for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) { - Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation(); - if (geolocation) - geolocation->suspend(); - } - - GET_NATIVE_VIEW(env, obj)->deviceMotionAndOrientationManager()->maybeSuspendClients(); - - ANPEvent event; - SkANP::InitEvent(&event, kLifecycle_ANPEventType); - event.data.lifecycle.action = kPause_ANPLifecycleAction; - GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event); - - GET_NATIVE_VIEW(env, obj)->setIsPaused(true); -} - -static void Resume(JNIEnv* env, jobject obj) -{ - Frame* mainFrame = GET_NATIVE_VIEW(env, obj)->mainFrame(); - for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) { - Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation(); - if (geolocation) - geolocation->resume(); - } - - GET_NATIVE_VIEW(env, obj)->deviceMotionAndOrientationManager()->maybeResumeClients(); - - ANPEvent event; - SkANP::InitEvent(&event, kLifecycle_ANPEventType); - event.data.lifecycle.action = kResume_ANPLifecycleAction; - GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event); - - GET_NATIVE_VIEW(env, obj)->setIsPaused(false); -} - -static void FreeMemory(JNIEnv* env, jobject obj) -{ - ANPEvent event; - SkANP::InitEvent(&event, kLifecycle_ANPEventType); - event.data.lifecycle.action = kFreeMemory_ANPLifecycleAction; - GET_NATIVE_VIEW(env, obj)->sendPluginEvent(event); -} - -static void ProvideVisitedHistory(JNIEnv *env, jobject obj, jobject hist) -{ - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__); - - jobjectArray array = static_cast<jobjectArray>(hist); - - jsize len = env->GetArrayLength(array); - for (jsize i = 0; i < len; i++) { - jstring item = static_cast<jstring>(env->GetObjectArrayElement(array, i)); - const UChar* str = static_cast<const UChar*>(env->GetStringChars(item, 0)); - jsize len = env->GetStringLength(item); - viewImpl->addVisitedLink(str, len); - env->ReleaseStringChars(item, str); - env->DeleteLocalRef(item); - } -} - -// Notification from the UI thread that the plugin's full-screen surface has been discarded -static void FullScreenPluginHidden(JNIEnv* env, jobject obj, jint npp) -{ - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - 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) -{ - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - 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].right(), rects[i].bottom()); - if (rect) { - env->CallBooleanMethod(array, add, rect); - env->DeleteLocalRef(rect); - } - } - - env->DeleteLocalRef(rectClass); - env->DeleteLocalRef(arrayClass); - return array; -} - -static void AutoFillForm(JNIEnv* env, jobject obj, jint queryId) -{ -#if ENABLE(WEB_AUTOFILL) - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - if (!viewImpl) - return; - - WebCore::Frame* frame = viewImpl->mainFrame(); - if (frame) { - EditorClientAndroid* editorC = static_cast<EditorClientAndroid*>(frame->page()->editorClient()); - WebAutoFill* autoFill = editorC->getAutoFill(); - autoFill->fillFormFields(queryId); - } -#endif -} - -static void ScrollRenderLayer(JNIEnv* env, jobject obj, jint layer, jobject jRect) -{ - SkRect rect; - GraphicsJNI::jrect_to_rect(env, jRect, &rect); - GET_NATIVE_VIEW(env, obj)->scrollRenderLayer(layer, rect); -} - -// ---------------------------------------------------------------------------- - -/* - * JNI registration. - */ -static JNINativeMethod gJavaWebViewCoreMethods[] = { - { "nativeClearContent", "()V", - (void*) ClearContent }, - { "nativeFocusBoundsChanged", "()Z", - (void*) FocusBoundsChanged } , - { "nativeKey", "(IIIZZZZ)Z", - (void*) Key }, - { "nativeClick", "(IIZ)V", - (void*) Click }, - { "nativeContentInvalidateAll", "()V", - (void*) ContentInvalidateAll }, - { "nativeSendListBoxChoices", "([ZI)V", - (void*) SendListBoxChoices }, - { "nativeSendListBoxChoice", "(I)V", - (void*) SendListBoxChoice }, - { "nativeSetSize", "(IIIFIIIIZ)V", - (void*) SetSize }, - { "nativeSetScrollOffset", "(IZII)V", - (void*) SetScrollOffset }, - { "nativeSetGlobalBounds", "(IIII)V", - (void*) SetGlobalBounds }, - { "nativeSetSelection", "(II)V", - (void*) SetSelection } , - { "nativeModifySelection", "(II)Ljava/lang/String;", - (void*) ModifySelection }, - { "nativeDeleteSelection", "(III)V", - (void*) DeleteSelection } , - { "nativeReplaceTextfieldText", "(IILjava/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", - (void*) PassToJs }, - { "nativeScrollFocusedTextInput", "(FI)V", - (void*) ScrollFocusedTextInput }, - { "nativeSetFocusControllerActive", "(Z)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;", - (void*) RetrieveHref }, - { "nativeRetrieveAnchorText", "(II)Ljava/lang/String;", - (void*) RetrieveAnchorText }, - { "nativeRetrieveImageSource", "(II)Ljava/lang/String;", - (void*) RetrieveImageSource }, - { "nativeStopPaintingCaret", "()V", - (void*) StopPaintingCaret }, - { "nativeUpdateFrameCache", "()V", - (void*) UpdateFrameCache }, - { "nativeGetContentMinPrefWidth", "()I", - (void*) GetContentMinPrefWidth }, - { "nativeUpdateLayers", "(Landroid/graphics/Region;)I", - (void*) UpdateLayers }, - { "nativeRecordContent", "(Landroid/graphics/Region;Landroid/graphics/Point;)I", - (void*) RecordContent }, - { "setViewportSettingsFromNative", "()V", - (void*) SetViewportSettingsFromNative }, - { "nativeSplitContent", "(I)V", - (void*) SplitContent }, - { "nativeSetBackgroundColor", "(I)V", - (void*) SetBackgroundColor }, - { "nativeRegisterURLSchemeAsLocal", "(Ljava/lang/String;)V", - (void*) RegisterURLSchemeAsLocal }, - { "nativeDumpDomTree", "(Z)V", - (void*) DumpDomTree }, - { "nativeDumpRenderTree", "(Z)V", - (void*) DumpRenderTree }, - { "nativeDumpNavTree", "()V", - (void*) DumpNavTree }, - { "nativeDumpV8Counters", "()V", - (void*) DumpV8Counters }, - { "nativeSetNewStorageLimit", "(J)V", - (void*) SetNewStorageLimit }, - { "nativeGeolocationPermissionsProvide", "(Ljava/lang/String;ZZ)V", - (void*) GeolocationPermissionsProvide }, - { "nativePause", "()V", (void*) Pause }, - { "nativeResume", "()V", (void*) Resume }, - { "nativeFreeMemory", "()V", (void*) FreeMemory }, - { "nativeSetJsFlags", "(Ljava/lang/String;)V", (void*) SetJsFlags }, - { "nativeRequestLabel", "(II)Ljava/lang/String;", - (void*) RequestLabel }, - { "nativeRevealSelection", "()V", (void*) RevealSelection }, - { "nativeUpdateFrameCacheIfLoading", "()V", - (void*) UpdateFrameCacheIfLoading }, - { "nativeProvideVisitedHistory", "([Ljava/lang/String;)V", - (void*) ProvideVisitedHistory }, - { "nativeFullScreenPluginHidden", "(I)V", - (void*) FullScreenPluginHidden }, - { "nativeValidNodeAndBounds", "(IILandroid/graphics/Rect;)Z", - (void*) ValidNodeAndBounds }, - { "nativeGetTouchHighlightRects", "(III)Ljava/util/ArrayList;", - (void*) GetTouchHighlightRects }, - { "nativeAutoFillForm", "(I)V", - (void*) AutoFillForm }, - { "nativeScrollLayer", "(ILandroid/graphics/Rect;)V", - (void*) ScrollRenderLayer }, -}; - -int registerWebViewCore(JNIEnv* env) -{ - jclass widget = env->FindClass("android/webkit/WebViewCore"); - LOG_ASSERT(widget, - "Unable to find class android/webkit/WebViewCore"); - gWebViewCoreFields.m_nativeClass = env->GetFieldID(widget, "mNativeClass", - "I"); - LOG_ASSERT(gWebViewCoreFields.m_nativeClass, - "Unable to find android/webkit/WebViewCore.mNativeClass"); - gWebViewCoreFields.m_viewportWidth = env->GetFieldID(widget, - "mViewportWidth", "I"); - LOG_ASSERT(gWebViewCoreFields.m_viewportWidth, - "Unable to find android/webkit/WebViewCore.mViewportWidth"); - gWebViewCoreFields.m_viewportHeight = env->GetFieldID(widget, - "mViewportHeight", "I"); - LOG_ASSERT(gWebViewCoreFields.m_viewportHeight, - "Unable to find android/webkit/WebViewCore.mViewportHeight"); - gWebViewCoreFields.m_viewportInitialScale = env->GetFieldID(widget, - "mViewportInitialScale", "I"); - LOG_ASSERT(gWebViewCoreFields.m_viewportInitialScale, - "Unable to find android/webkit/WebViewCore.mViewportInitialScale"); - gWebViewCoreFields.m_viewportMinimumScale = env->GetFieldID(widget, - "mViewportMinimumScale", "I"); - LOG_ASSERT(gWebViewCoreFields.m_viewportMinimumScale, - "Unable to find android/webkit/WebViewCore.mViewportMinimumScale"); - gWebViewCoreFields.m_viewportMaximumScale = env->GetFieldID(widget, - "mViewportMaximumScale", "I"); - LOG_ASSERT(gWebViewCoreFields.m_viewportMaximumScale, - "Unable to find android/webkit/WebViewCore.mViewportMaximumScale"); - gWebViewCoreFields.m_viewportUserScalable = env->GetFieldID(widget, - "mViewportUserScalable", "Z"); - LOG_ASSERT(gWebViewCoreFields.m_viewportUserScalable, - "Unable to find android/webkit/WebViewCore.mViewportUserScalable"); - gWebViewCoreFields.m_viewportDensityDpi = env->GetFieldID(widget, - "mViewportDensityDpi", "I"); - LOG_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, - "Unable to find android/webkit/WebViewCore.mDrawIsPaused"); - gWebViewCoreFields.m_lowMemoryUsageMb = env->GetFieldID(widget, "mLowMemoryUsageThresholdMb", "I"); - gWebViewCoreFields.m_highMemoryUsageMb = env->GetFieldID(widget, "mHighMemoryUsageThresholdMb", "I"); - gWebViewCoreFields.m_highUsageDeltaMb = env->GetFieldID(widget, "mHighUsageDeltaMb", "I"); - - gWebViewCoreStaticMethods.m_isSupportedMediaMimeType = - env->GetStaticMethodID(widget, "isSupportedMediaMimeType", "(Ljava/lang/String;)Z"); - LOG_FATAL_IF(!gWebViewCoreStaticMethods.m_isSupportedMediaMimeType, - "Could not find static method isSupportedMediaMimeType from WebViewCore"); - - env->DeleteLocalRef(widget); - - return jniRegisterNativeMethods(env, "android/webkit/WebViewCore", - gJavaWebViewCoreMethods, NELEM(gJavaWebViewCoreMethods)); -} - -} /* namespace android */ |
