summaryrefslogtreecommitdiff
path: root/Source/WebKit2/UIProcess/qt
diff options
context:
space:
mode:
authorAndras Becsi <andras.becsi@digia.com>2013-03-20 18:54:42 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-03-25 17:44:32 +0100
commitf17185389d49fd4781e6745df59a71ad0270a1d0 (patch)
tree84db31d6f6180cd5bbbc9fa903b7b1e372fde155 /Source/WebKit2/UIProcess/qt
parent2f903ee40150a6db52749a2a8ac086d9fbadbbbc (diff)
downloadqtwebkit-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/WebKit2/UIProcess/qt')
-rw-r--r--Source/WebKit2/UIProcess/qt/PageViewportControllerClientQt.cpp79
-rw-r--r--Source/WebKit2/UIProcess/qt/PageViewportControllerClientQt.h26
2 files changed, 77 insertions, 28 deletions
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