From 2eba477ffa722f0b9838f21f65b6493515083d19 Mon Sep 17 00:00:00 2001 From: Grace Kloba Date: Sat, 23 Jan 2010 10:09:03 -0800 Subject: [PATCH] Merge pinch zoom from Eclair to Master. Including, commit 237bd75b6ebc1298cbd1c46b43903d19d7dd18b1 commit dbb3061334333f32b6f12c294a551bd2a4a3844c commit f48712a096831a3b85a5e18dabd44a541f6b4712 commit b99dd716b4af0afde074e28b50b7b28ae3c03da7 --- WebKit/android/jni/WebViewCore.cpp | 105 +++++++++++++++++++++++++++---------- WebKit/android/jni/WebViewCore.h | 13 ++++- 2 files changed, 89 insertions(+), 29 deletions(-) diff --git a/WebKit/android/jni/WebViewCore.cpp b/WebKit/android/jni/WebViewCore.cpp index 5ebc8eb2c..9778ea0ed 100644 --- a/WebKit/android/jni/WebViewCore.cpp +++ b/WebKit/android/jni/WebViewCore.cpp @@ -229,6 +229,7 @@ struct WebViewCore::JavaGlue { jmethodID m_destroySurface; jmethodID m_getContext; jmethodID m_sendFindAgain; + jmethodID m_showRect; AutoJObject object(JNIEnv* env) { return getRealObject(env, m_obj); } @@ -314,6 +315,7 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m m_javaGlue->m_destroySurface = GetJMethod(env, clazz, "destroySurface", "(Landroid/webkit/ViewManager$ChildView;)V"); m_javaGlue->m_getContext = GetJMethod(env, clazz, "getContext", "()Landroid/content/Context;"); m_javaGlue->m_sendFindAgain = GetJMethod(env, clazz, "sendFindAgain", "()V"); + m_javaGlue->m_showRect = GetJMethod(env, clazz, "showRect", "(IIIIIIFFFF)V"); env->SetIntField(javaWebViewCore, gWebViewCoreFields.m_nativeClass, (jint)this); @@ -1099,13 +1101,15 @@ void WebViewCore::setGlobalBounds(int x, int y, int h, int v) void WebViewCore::setSizeScreenWidthAndScale(int width, int height, int screenWidth, float scale, int realScreenWidth, int screenHeight, - bool ignoreHeight) + int anchorX, int anchorY, bool ignoreHeight) { WebCoreViewBridge* window = m_mainFrame->view()->platformWidget(); int ow = window->width(); int oh = window->height(); window->setSize(width, height); int osw = m_screenWidth; + int orsw = m_screenWidth * m_screenWidthScale / m_scale; + int osh = m_screenHeight; 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; @@ -1124,46 +1128,82 @@ void WebViewCore::setSizeScreenWidthAndScale(int width, int height, DBG_NAV_LOGD("renderer=%p view=(w=%d,h=%d)", r, realScreenWidth, screenHeight); if (r) { - // get current screen center position - WebCore::IntPoint screenCenter = WebCore::IntPoint( - m_scrollOffsetX + (realScreenWidth >> 1), - m_scrollOffsetY + (screenHeight >> 1)); + WebCore::IntPoint anchorPoint; + if ((anchorX | anchorY) == 0) + // get the current screen center position if anchor is (0, 0) + // which implies that it is not defined + anchorPoint = WebCore::IntPoint( + m_scrollOffsetX + (realScreenWidth >> 1), + m_scrollOffsetY + (screenHeight >> 1)); + else + anchorPoint = WebCore::IntPoint(anchorX, anchorY); WebCore::Node* node = 0; WebCore::IntRect bounds; WebCore::IntPoint offset; // If the screen width changed, it is probably zoom change or - // orientation change. Try to keep the node in the center of the - // screen staying at the same place. - if (osw != screenWidth) { + // orientation change. Try to keep the anchor at the same place. + if (osw && screenWidth && osw != screenWidth) { WebCore::HitTestResult hitTestResult = m_mainFrame->eventHandler()-> hitTestResultAtPoint( - screenCenter, false); + 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()); - offset = WebCore::IntPoint(screenCenter.x() - bounds.x(), - screenCenter.y() - bounds.y()); - if (offset.x() < 0 || offset.x() > realScreenWidth || - offset.y() < 0 || offset.y() > screenHeight) - { - DBG_NAV_LOGD("offset out of bounds:(x=%d,y=%d)", - offset.x(), offset.y()); - node = 0; + // sites like nytimes.com insert a non-standard tag + // 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->parent(); + 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()); + } + } + if ((anchorX | anchorY) == 0) { + // if there is no explicit anchor, ignore if it is offscreen + offset = WebCore::IntPoint(anchorPoint.x() - bounds.x(), + anchorPoint.y() - bounds.y()); + if (offset.x() < 0 || offset.x() > realScreenWidth || + offset.y() < 0 || offset.y() > screenHeight) + { + DBG_NAV_LOGD("offset out of bounds:(x=%d,y=%d)", + offset.x(), offset.y()); + node = 0; + } } } 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,ns=%d)", newBounds.x(), newBounds.y(), - newBounds.width(), newBounds.height()); - scrollBy(newBounds.x() - bounds.x(), newBounds.y() - bounds.y(), - false); + if (!node) + return; + 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 ((anchorX | anchorY) == 0) + scrollBy(newBounds.x() - bounds.x(), + newBounds.y() - bounds.y(), false); + else if ((orsw && 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. + bool leftAlign = (osw != m_screenWidth) + && (bounds.width() == newBounds.width()) + && (bounds.height() != newBounds.height()); + showRect(newBounds.x(), newBounds.y(), newBounds.width(), + newBounds.height(), view->contentsWidth(), + view->contentsHeight(), + leftAlign ? 0.0 : (float) (anchorX - bounds.x()) / bounds.width(), + leftAlign ? 0.0 : (float) (anchorX - m_scrollOffsetX) / orsw, + (float) (anchorY - bounds.y()) / bounds.height(), + (float) (anchorY - m_scrollOffsetY) / osh); } } } @@ -2398,6 +2438,17 @@ bool WebViewCore::validNodeAndBounds(Frame* frame, Node* node, 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); +} + //---------------------------------------------------------------------- // Native JNI methods //---------------------------------------------------------------------- @@ -2425,7 +2476,7 @@ static void UpdateFrameCacheIfLoading(JNIEnv *env, jobject obj) static void SetSize(JNIEnv *env, jobject obj, jint width, jint height, jint screenWidth, jfloat scale, jint realScreenWidth, jint screenHeight, - jboolean ignoreHeight) + jint anchorX, jint anchorY, jboolean ignoreHeight) { #ifdef ANDROID_INSTRUMENT TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); @@ -2434,7 +2485,7 @@ static void SetSize(JNIEnv *env, jobject obj, jint width, jint height, 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, screenWidth, scale, - realScreenWidth, screenHeight, ignoreHeight); + realScreenWidth, screenHeight, anchorX, anchorY, ignoreHeight); } static void SetScrollOffset(JNIEnv *env, jobject obj, jint gen, jint x, jint y) @@ -3022,7 +3073,7 @@ static JNINativeMethod gJavaWebViewCoreMethods[] = { (void*) SendListBoxChoices }, { "nativeSendListBoxChoice", "(I)V", (void*) SendListBoxChoice }, - { "nativeSetSize", "(IIIFIIZ)V", + { "nativeSetSize", "(IIIFIIIIZ)V", (void*) SetSize }, { "nativeSetScrollOffset", "(III)V", (void*) SetScrollOffset }, diff --git a/WebKit/android/jni/WebViewCore.h b/WebKit/android/jni/WebViewCore.h index c6624415b..f528c7365 100644 --- a/WebKit/android/jni/WebViewCore.h +++ b/WebKit/android/jni/WebViewCore.h @@ -265,8 +265,8 @@ namespace android { void setGlobalBounds(int x, int y, int h, int v); void setSizeScreenWidthAndScale(int width, int height, int screenWidth, - float scale, int realScreenWidth, int screenHeight, - bool ignoreHeight); + float scale, int realScreenWidth, int screenHeight, int anchorX, + int anchorY, bool ignoreHeight); /** * Handle key events from Java. @@ -405,6 +405,15 @@ namespace android { jobject getContext(); bool validNodeAndBounds(Frame* , Node* , const IntRect& ); + + // Make the rect (left, top, width, height) visible. If it can be fully + // fit, center it on the screen. Otherwise make sure the point specified + // by (left + xPercentInDoc * width, top + yPercentInDoc * height) + // pinned at the screen position (xPercentInView, yPercentInView). + void showRect(int left, int top, int width, int height, int contentWidth, + int contentHeight, float xPercentInDoc, float xPercentInView, + float yPercentInDoc, float yPercentInView); + // other public functions public: // Open a file chooser for selecting a file to upload -- 2.11.0