diff options
author | Andras Becsi <andras.becsi@digia.com> | 2013-03-20 18:54:42 +0100 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-03-25 17:44:32 +0100 |
commit | f17185389d49fd4781e6745df59a71ad0270a1d0 (patch) | |
tree | 84db31d6f6180cd5bbbc9fa903b7b1e372fde155 /Source | |
parent | 2f903ee40150a6db52749a2a8ac086d9fbadbbbc (diff) | |
download | qtwebkit-f17185389d49fd4781e6745df59a71ad0270a1d0.tar.gz |
Refactor handling of content suspension to properly cover corner cases
https://bugs.webkit.org/show_bug.cgi?id=111751
This is a back-port from upstream patch http://trac.webkit.org/changeset/146355
Reviewed by Jocelyn Turcotte.
The current suspend / resume infrastructure turned out to be insufficient to cover
all corner cases during transitions between gestures of complex gesture chains.
The requirements for robust suspend / resume handling are:
- Keep the content suspended while the user is continuously interacting,
eg. does not lift the finger between transition from a pan to a pinch gesture
and vice versa.
- The content should not be suspended unnecessarily (like for a tap gesture),
only during panning and scroll animation (flick), as well as pinch zoom and scale
animation (also includes double-tap-to-zoom).
- The content should never end up stuck in suspended state after long gesture
chains and continuous interaction.
This patch reintroduces reference counting based suspension in form of a new
ViewportInteractionTracker member class to make it possible to reliably control the
suspend / resume cycles during scrolling and scaling.
During continuous gestures, while the user is interacting, the reference count is
increased without actually suspending the content to prevent resuming unnecessarily
during continuous interaction. At the same time this also assures that the page is
not suspended for simple tap gestures, which was a side-effect of the previous
approach based on update deferrers.
The newly added functionality replaces boolean members that tried to achive the
above requirements.
Additionally this patch also removes the redundant m_hasSuspendedContent member
from the PageViewportController since WebPageProxy already keeps this information.
Change-Id: Id9b55d37c7ad839a27029e92872f36bbf202e660
Reviewed-by: Jocelyn Turcotte <jocelyn.turcotte@digia.com>
Diffstat (limited to 'Source')
5 files changed, 80 insertions, 60 deletions
diff --git a/Source/WebKit2/UIProcess/PageViewportController.cpp b/Source/WebKit2/UIProcess/PageViewportController.cpp index 05ff8b98a..a34782c8f 100644 --- a/Source/WebKit2/UIProcess/PageViewportController.cpp +++ b/Source/WebKit2/UIProcess/PageViewportController.cpp @@ -45,7 +45,6 @@ PageViewportController::PageViewportController(WebKit::WebPageProxy* proxy, Page , m_allowsUserScaling(false) , m_minimumScaleToFit(1) , m_initiallyFitToViewport(true) - , m_hasSuspendedContent(false) , m_hadUserInteraction(false) , m_pageScaleFactor(1) , m_viewportPosIsLocked(false) @@ -177,7 +176,7 @@ void PageViewportController::pageTransitionViewportReady() void PageViewportController::pageDidRequestScroll(const IntPoint& cssPosition) { // Ignore the request if suspended. Can only happen due to delay in event delivery. - if (m_hasSuspendedContent) + if (m_webPageProxy->areActiveDOMObjectsAndAnimationsSuspended()) return; FloatRect endVisibleContentRect(clampViewportToContents(cssPosition, m_pageScaleFactor), viewportSizeInContentsCoordinates()); @@ -246,26 +245,6 @@ WebCore::FloatSize PageViewportController::viewportSizeInContentsCoordinates() c return WebCore::FloatSize(m_viewportSize.width() / m_pageScaleFactor, m_viewportSize.height() / m_pageScaleFactor); } -void PageViewportController::suspendContent() -{ - if (m_hasSuspendedContent) - return; - - m_hasSuspendedContent = true; - m_webPageProxy->suspendActiveDOMObjectsAndAnimations(); -} - -void PageViewportController::resumeContent() -{ - m_client->didResumeContent(); - - if (!m_hasSuspendedContent) - return; - - m_hasSuspendedContent = false; - m_webPageProxy->resumeActiveDOMObjectsAndAnimations(); -} - void PageViewportController::applyScaleAfterRenderingContents(float scale) { m_pageScaleFactor = scale; @@ -295,7 +274,7 @@ bool PageViewportController::updateMinimumScaleToFit(bool userInitiatedUpdate) if (!fuzzyCompare(minimumScale, m_minimumScaleToFit, 0.001)) { m_minimumScaleToFit = minimumScale; - if (!hasSuspendedContent()) { + if (!m_webPageProxy->areActiveDOMObjectsAndAnimationsSuspended()) { if (!m_hadUserInteraction || (userInitiatedUpdate && currentlyScaledToFit)) applyScaleAfterRenderingContents(m_minimumScaleToFit); else { diff --git a/Source/WebKit2/UIProcess/PageViewportController.h b/Source/WebKit2/UIProcess/PageViewportController.h index dadbbbefe..fcc4e170d 100644 --- a/Source/WebKit2/UIProcess/PageViewportController.h +++ b/Source/WebKit2/UIProcess/PageViewportController.h @@ -22,8 +22,6 @@ #ifndef PageViewportController_h #define PageViewportController_h -#if USE(TILED_BACKING_STORE) - #include <WebCore/FloatPoint.h> #include <WebCore/FloatRect.h> #include <WebCore/FloatSize.h> @@ -47,14 +45,10 @@ public: PageViewportController(WebKit::WebPageProxy*, PageViewportControllerClient*); virtual ~PageViewportController() { } - void suspendContent(); - void resumeContent(); - float innerBoundedViewportScale(float) const; float outerBoundedViewportScale(float) const; WebCore::FloatPoint clampViewportToContents(const WebCore::FloatPoint& viewportPos, float viewportScale); - bool hasSuspendedContent() const { return m_hasSuspendedContent; } bool hadUserInteraction() const { return m_hadUserInteraction; } bool allowsUserScaling() const { return m_allowsUserScaling; } @@ -94,7 +88,6 @@ private: float m_minimumScaleToFit; bool m_initiallyFitToViewport; - bool m_hasSuspendedContent; bool m_hadUserInteraction; WebCore::FloatPoint m_viewportPos; @@ -112,6 +105,4 @@ bool fuzzyCompare(float, float, float epsilon); } // namespace WebKit -#endif - #endif // PageViewportController_h diff --git a/Source/WebKit2/UIProcess/WebPageProxy.h b/Source/WebKit2/UIProcess/WebPageProxy.h index ff8ec5133..1b2e9a2b7 100644 --- a/Source/WebKit2/UIProcess/WebPageProxy.h +++ b/Source/WebKit2/UIProcess/WebPageProxy.h @@ -472,6 +472,7 @@ public: void setCustomTextEncodingName(const String&); String customTextEncodingName() const { return m_customTextEncodingName; } + bool areActiveDOMObjectsAndAnimationsSuspended() const { return m_isPageSuspended; } void resumeActiveDOMObjectsAndAnimations(); void suspendActiveDOMObjectsAndAnimations(); diff --git a/Source/WebKit2/UIProcess/qt/PageViewportControllerClientQt.cpp b/Source/WebKit2/UIProcess/qt/PageViewportControllerClientQt.cpp index c0eb16ab9..61f2aaf57 100644 --- a/Source/WebKit2/UIProcess/qt/PageViewportControllerClientQt.cpp +++ b/Source/WebKit2/UIProcess/qt/PageViewportControllerClientQt.cpp @@ -23,12 +23,14 @@ #include "config.h" #include "PageViewportControllerClientQt.h" +#include "WebPageProxy.h" #include "qquickwebpage_p.h" #include "qquickwebview_p.h" #include "qwebkittest_p.h" #include <QPointF> #include <QTransform> #include <QtQuick/qquickitem.h> +#include <WKAPICast.h> #include <WebCore/FloatRect.h> #include <WebCore/FloatSize.h> @@ -41,12 +43,14 @@ static const int kScaleAnimationDurationMillis = 250; PageViewportControllerClientQt::PageViewportControllerClientQt(QQuickWebView* viewportItem, QQuickWebPage* pageItem) : m_viewportItem(viewportItem) , m_pageItem(pageItem) + , m_scaleChange(this) + , m_scrollChange(this) + , m_touchInteraction(this, false /* shouldSuspend */) , m_scaleAnimation(new ScaleAnimation(this)) + , m_activeInteractionCount(0) , m_pinchStartScale(-1) , m_lastCommittedScale(-1) , m_zoomOutScale(0) - , m_isUserInteracting(false) - , m_ignoreViewportChanges(false) { m_scaleAnimation->setDuration(kScaleAnimationDurationMillis); m_scaleAnimation->setEasingCurve(QEasingCurve::OutCubic); @@ -76,6 +80,32 @@ void PageViewportControllerClientQt::ScaleAnimation::updateCurrentValue(const QV m_controllerClient->setContentRectVisiblePositionAtScale(itemRect.topLeft(), itemScale); } +void PageViewportControllerClientQt::ViewportInteractionTracker::begin() +{ + if (m_inProgress) + return; + + m_inProgress = true; + + if (m_shouldSuspend) + toImpl(m_controllerClient->m_viewportItem->pageRef())->suspendActiveDOMObjectsAndAnimations(); + + ++(m_controllerClient->m_activeInteractionCount); +} + +void PageViewportControllerClientQt::ViewportInteractionTracker::end() +{ + if (!m_inProgress) + return; + + m_inProgress = false; + + ASSERT(m_controllerClient->m_activeInteractionCount > 0); + + if (!(--(m_controllerClient->m_activeInteractionCount))) + toImpl(m_controllerClient->m_viewportItem->pageRef())->resumeActiveDOMObjectsAndAnimations(); +} + PageViewportControllerClientQt::~PageViewportControllerClientQt() { } @@ -103,7 +133,8 @@ void PageViewportControllerClientQt::animateContentRectVisible(const QRectF& con QRectF viewportRectInContentCoords = m_viewportItem->mapRectToWebContent(m_viewportItem->boundingRect()); if (contentRect == viewportRectInContentCoords) { - m_controller->resumeContent(); + m_scaleChange.end(); + updateViewportController(); return; } @@ -121,22 +152,20 @@ void PageViewportControllerClientQt::animateContentRectVisible(const QRectF& con void PageViewportControllerClientQt::flickMoveStarted() { - m_controller->suspendContent(); - + m_scrollChange.begin(); m_lastScrollPosition = m_viewportItem->contentPos(); } void PageViewportControllerClientQt::flickMoveEnded() { // This method is called on the end of the pan or pan kinetic animation. - - if (!m_isUserInteracting) - m_controller->resumeContent(); + m_scrollChange.end(); + updateViewportController(); } void PageViewportControllerClientQt::pageItemPositionChanged() { - if (m_ignoreViewportChanges) + if (m_scaleChange.inProgress()) return; QPointF newPosition = m_viewportItem->contentPos(); @@ -150,13 +179,11 @@ void PageViewportControllerClientQt::scaleAnimationStateChanged(QAbstractAnimati { switch (newState) { case QAbstractAnimation::Running: - m_ignoreViewportChanges = true; - m_viewportItem->cancelFlick(); - m_controller->suspendContent(); + m_scaleChange.begin(); break; case QAbstractAnimation::Stopped: - m_ignoreViewportChanges = false; - m_controller->resumeContent(); + m_scaleChange.end(); + updateViewportController(); break; default: break; @@ -167,13 +194,14 @@ void PageViewportControllerClientQt::touchBegin() { m_controller->setHadUserInteraction(true); - // Prevents resuming the page between the user's flicks of the page. - m_isUserInteracting = true; + // Prevent resuming the page during transition between gestures while the user is interacting. + // The content is suspended as soon as a pan or pinch gesture or an animation is started. + m_touchInteraction.begin(); } void PageViewportControllerClientQt::touchEnd() { - m_isUserInteracting = false; + m_touchInteraction.end(); } void PageViewportControllerClientQt::focusEditableArea(const QRectF& caretArea, const QRectF& targetArea) @@ -217,7 +245,7 @@ void PageViewportControllerClientQt::zoomToAreaGestureEnded(const QPointF& touch if (!targetArea.isValid()) return; - if (m_controller->hasSuspendedContent()) + if (m_scrollChange.inProgress() || m_scaleChange.inProgress()) return; const float margin = 10; // We want at least a little bit of margin. @@ -425,9 +453,7 @@ void PageViewportControllerClientQt::pinchGestureStarted(const QPointF& pinchCen return; clearRelativeZoomState(); - - m_ignoreViewportChanges = true; - m_controller->suspendContent(); + m_scaleChange.begin(); m_lastPinchCenterInViewportCoordinates = pinchCenterInViewportCoordinates; m_pinchStartScale = m_pageItem->contentsScale(); @@ -435,11 +461,12 @@ void PageViewportControllerClientQt::pinchGestureStarted(const QPointF& pinchCen void PageViewportControllerClientQt::pinchGestureRequestUpdate(const QPointF& pinchCenterInViewportCoordinates, qreal totalScaleFactor) { - ASSERT(m_controller->hasSuspendedContent()); + ASSERT(m_scaleChange.inProgress()); if (!m_controller->allowsUserScaling()) return; + ASSERT(m_pinchStartScale > 0); // Changes of the center position should move the page even if the zoom factor does not change. const qreal pinchScale = m_pinchStartScale * totalScaleFactor; @@ -456,12 +483,11 @@ void PageViewportControllerClientQt::pinchGestureRequestUpdate(const QPointF& pi void PageViewportControllerClientQt::pinchGestureEnded() { - ASSERT(m_controller->hasSuspendedContent()); + ASSERT(m_scaleChange.inProgress()); if (!m_controller->allowsUserScaling()) return; - m_ignoreViewportChanges = false; m_pinchStartScale = -1; // This will take care of resuming the content, even if no animation was performed. @@ -471,7 +497,8 @@ void PageViewportControllerClientQt::pinchGestureEnded() void PageViewportControllerClientQt::pinchGestureCancelled() { m_pinchStartScale = -1; - m_controller->resumeContent(); + m_scaleChange.end(); + updateViewportController(); } void PageViewportControllerClientQt::didChangeContentsSize(const IntSize& newSize) @@ -482,7 +509,7 @@ void PageViewportControllerClientQt::didChangeContentsSize(const IntSize& newSiz // we didn't do scale adjustment. emit m_viewportItem->experimental()->test()->contentsScaleCommitted(); - if (!m_controller->hasSuspendedContent()) + if (!m_scaleChange.inProgress() && !m_scrollChange.inProgress()) setContentsRectToNearestValidBounds(); } diff --git a/Source/WebKit2/UIProcess/qt/PageViewportControllerClientQt.h b/Source/WebKit2/UIProcess/qt/PageViewportControllerClientQt.h index 687f29193..22c4c3d3c 100644 --- a/Source/WebKit2/UIProcess/qt/PageViewportControllerClientQt.h +++ b/Source/WebKit2/UIProcess/qt/PageViewportControllerClientQt.h @@ -103,6 +103,24 @@ private: virtual void updateCurrentValue(const QVariant&); }; + class ViewportInteractionTracker { + public: + ViewportInteractionTracker(PageViewportControllerClientQt* client, bool shouldSuspend = true) + : m_controllerClient(client) + , m_shouldSuspend(shouldSuspend) + , m_inProgress(false) + { } + + void begin(); + void end(); + bool inProgress() const { return m_inProgress; } + + private: + PageViewportControllerClientQt* m_controllerClient; + bool m_shouldSuspend; + bool m_inProgress; + }; + struct ScaleStackItem { ScaleStackItem(qreal scale, qreal xPosition) : scale(scale) @@ -113,6 +131,7 @@ private: qreal xPosition; }; + friend class ViewportInteractionTracker; friend class ScaleAnimation; friend class ::QWebKitTest; @@ -130,15 +149,18 @@ private: void scaleContent(qreal itemScale, const QPointF& centerInCSSCoordinates = QPointF()); void clearRelativeZoomState(); + ViewportInteractionTracker m_scaleChange; + ViewportInteractionTracker m_scrollChange; + ViewportInteractionTracker m_touchInteraction; + ScaleAnimation* m_scaleAnimation; QPointF m_lastPinchCenterInViewportCoordinates; QPointF m_lastScrollPosition; + int m_activeInteractionCount; qreal m_pinchStartScale; qreal m_lastCommittedScale; qreal m_zoomOutScale; QList<ScaleStackItem> m_scaleStack; - bool m_isUserInteracting; - bool m_ignoreViewportChanges; }; } // namespace WebKit |