mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 786267: B2G: Lower resolution while doing accelerated panning r=cjones
This commit is contained in:
parent
19cc16c9aa
commit
4a17f28103
@ -459,8 +459,10 @@ TabChild::HandlePossibleMetaViewportChange()
|
||||
metrics.mZoom.width = metrics.mZoom.height =
|
||||
metrics.mResolution.width = metrics.mResolution.height = zoom;
|
||||
metrics.mDisplayPort = AsyncPanZoomController::CalculatePendingDisplayPort(
|
||||
metrics,
|
||||
gfx::Point(0.0f, 0.0f));
|
||||
// The page must have been refreshed in some way such as a new document or
|
||||
// new CSS viewport, so we know that there's no velocity, acceleration, and
|
||||
// we have no idea how long painting will take.
|
||||
metrics, gfx::Point(0.0f, 0.0f), gfx::Point(0.0f, 0.0f), 0.0);
|
||||
// Force a repaint with these metrics. This, among other things, sets the
|
||||
// displayport, so we start with async painting.
|
||||
RecvUpdateFrame(metrics);
|
||||
|
@ -44,7 +44,7 @@ static const int32_t FLING_REPAINT_INTERVAL = 75;
|
||||
* Minimum amount of speed along an axis before we begin painting far ahead by
|
||||
* adjusting the displayport.
|
||||
*/
|
||||
static const float MIN_SKATE_SPEED = 0.5f;
|
||||
static const float MIN_SKATE_SPEED = 0.7f;
|
||||
|
||||
/**
|
||||
* Angle from axis within which we stay axis-locked.
|
||||
@ -79,6 +79,12 @@ static const double MIN_ZOOM = 0.125;
|
||||
*/
|
||||
static const int TOUCH_LISTENER_TIMEOUT = 300;
|
||||
|
||||
/**
|
||||
* Number of samples to store of how long it took to paint after the previous
|
||||
* requests.
|
||||
*/
|
||||
static const int NUM_PAINT_DURATION_SAMPLES = 3;
|
||||
|
||||
AsyncPanZoomController::AsyncPanZoomController(GeckoContentController* aGeckoContentController,
|
||||
GestureBehavior aGestures)
|
||||
: mGeckoContentController(aGeckoContentController),
|
||||
@ -587,6 +593,10 @@ const gfx::Point AsyncPanZoomController::GetVelocityVector() {
|
||||
return gfx::Point(mX.GetVelocity(), mY.GetVelocity());
|
||||
}
|
||||
|
||||
const gfx::Point AsyncPanZoomController::GetAccelerationVector() {
|
||||
return gfx::Point(mX.GetAccelerationFactor(), mY.GetAccelerationFactor());
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::StartPanning(const MultiTouchInput& aEvent) {
|
||||
float dx = mX.PanDistance(),
|
||||
dy = mY.PanDistance();
|
||||
@ -661,6 +671,9 @@ bool AsyncPanZoomController::DoFling(const TimeDuration& aDelta) {
|
||||
shouldContinueFlingY = mY.FlingApplyFrictionOrCancel(aDelta);
|
||||
// If we shouldn't continue the fling, let's just stop and repaint.
|
||||
if (!shouldContinueFlingX && !shouldContinueFlingY) {
|
||||
// Bring the resolution back in sync with the zoom, in case we scaled down
|
||||
// the zoom while accelerating.
|
||||
SetZoomAndResolution(mFrameMetrics.mZoom.width);
|
||||
RequestContentRepaint();
|
||||
mState = NOTHING;
|
||||
return false;
|
||||
@ -712,8 +725,7 @@ void AsyncPanZoomController::SetPageRect(const gfx::Rect& aCSSPageRect) {
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::ScaleWithFocus(float aScale, const nsIntPoint& aFocus) {
|
||||
float scaleFactor = aScale / mFrameMetrics.mZoom.width,
|
||||
oldScale = mFrameMetrics.mZoom.width;
|
||||
float scaleFactor = aScale / mFrameMetrics.mZoom.width;
|
||||
|
||||
SetZoomAndResolution(aScale);
|
||||
|
||||
@ -721,22 +733,43 @@ void AsyncPanZoomController::ScaleWithFocus(float aScale, const nsIntPoint& aFoc
|
||||
// current CSS page rect (which is unchanged since it's not affected by zoom).
|
||||
SetPageRect(mFrameMetrics.mScrollableRect);
|
||||
|
||||
mFrameMetrics.mScrollOffset.x += float(aFocus.x) * (scaleFactor - 1.0f) / oldScale;
|
||||
mFrameMetrics.mScrollOffset.y += float(aFocus.y) * (scaleFactor - 1.0f) / oldScale;
|
||||
// If the new scale is very small, we risk multiplying in huge rounding
|
||||
// errors, so don't bother adjusting the scroll offset.
|
||||
if (aScale >= 0.01f) {
|
||||
mFrameMetrics.mScrollOffset.x += float(aFocus.x) * (scaleFactor - 1.0f) / aScale;
|
||||
mFrameMetrics.mScrollOffset.y += float(aFocus.y) * (scaleFactor - 1.0f) / aScale;
|
||||
}
|
||||
}
|
||||
|
||||
bool AsyncPanZoomController::EnlargeDisplayPortAlongAxis(float aCompositionBounds,
|
||||
bool AsyncPanZoomController::EnlargeDisplayPortAlongAxis(float aSkateSizeMultiplier,
|
||||
double aEstimatedPaintDuration,
|
||||
float aCompositionBounds,
|
||||
float aVelocity,
|
||||
float aAcceleration,
|
||||
float* aDisplayPortOffset,
|
||||
float* aDisplayPortLength)
|
||||
{
|
||||
const float MIN_SKATE_SIZE_MULTIPLIER = 2.0f;
|
||||
const float MAX_SKATE_SIZE_MULTIPLIER = 4.0f;
|
||||
|
||||
if (fabsf(aVelocity) > MIN_SKATE_SPEED) {
|
||||
*aDisplayPortLength = aCompositionBounds * clamped(fabsf(aVelocity),
|
||||
MIN_SKATE_SIZE_MULTIPLIER, MAX_SKATE_SIZE_MULTIPLIER);
|
||||
// Enlarge the area we paint.
|
||||
*aDisplayPortLength = aCompositionBounds * aSkateSizeMultiplier;
|
||||
// Position the area we paint such that all of the excess that extends past
|
||||
// the screen is on the side towards the velocity.
|
||||
*aDisplayPortOffset = aVelocity > 0 ? 0 : aCompositionBounds - *aDisplayPortLength;
|
||||
|
||||
// Only compensate for acceleration when we actually have any. Otherwise
|
||||
// we'll overcompensate when a user is just panning around without flinging.
|
||||
if (aAcceleration > 1.01f) {
|
||||
// Compensate for acceleration and how long we expect a paint to take. We
|
||||
// try to predict where the viewport will be when painting has finished.
|
||||
*aDisplayPortOffset +=
|
||||
fabsf(aAcceleration) * aVelocity * aCompositionBounds * aEstimatedPaintDuration;
|
||||
// If our velocity is in the negative direction of the axis, we have to
|
||||
// compensate for the fact that our scroll offset is the top-left position
|
||||
// of the viewport. In this case, let's make it relative to the
|
||||
// bottom-right. That way, we'll always be growing the displayport upwards
|
||||
// and to the left when skating negatively.
|
||||
*aDisplayPortOffset -= aVelocity < 0 ? aCompositionBounds : 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -744,36 +777,85 @@ bool AsyncPanZoomController::EnlargeDisplayPortAlongAxis(float aCompositionBound
|
||||
|
||||
const gfx::Rect AsyncPanZoomController::CalculatePendingDisplayPort(
|
||||
const FrameMetrics& aFrameMetrics,
|
||||
const gfx::Point& aVelocity)
|
||||
const gfx::Point& aVelocity,
|
||||
const gfx::Point& aAcceleration,
|
||||
double aEstimatedPaintDuration)
|
||||
{
|
||||
// The multiplier we apply to a dimension's length if it is skating. That is,
|
||||
// if it's going above MIN_SKATE_SPEED. We prefer to increase the size of the
|
||||
// Y axis because it is more natural in the case that a user is reading a page
|
||||
// that scrolls up/down. Note that one, both or neither of these may be used
|
||||
// at any instant.
|
||||
const float X_SKATE_SIZE_MULTIPLIER = 3.0f;
|
||||
const float Y_SKATE_SIZE_MULTIPLIER = 3.5f;
|
||||
|
||||
// The multiplier we apply to a dimension's length if it is stationary. We
|
||||
// prefer to increase the size of the Y axis because it is more natural in the
|
||||
// case that a user is reading a page that scrolls up/down. Note that one,
|
||||
// both or neither of these may be used at any instant.
|
||||
const float X_STATIONARY_SIZE_MULTIPLIER = 1.5f;
|
||||
const float Y_STATIONARY_SIZE_MULTIPLIER = 2.5f;
|
||||
|
||||
// If we don't get an estimated paint duration, we probably don't have any
|
||||
// data. In this case, we're dealing with either a stationary frame or a first
|
||||
// paint. In either of these cases, we can just assume it'll take 1 second to
|
||||
// paint. Getting this correct is not important anyways since it's only really
|
||||
// useful when accelerating, which can't be happening at this point.
|
||||
double estimatedPaintDuration =
|
||||
aEstimatedPaintDuration > EPSILON ? aEstimatedPaintDuration : 1.0;
|
||||
|
||||
float scale = aFrameMetrics.mZoom.width;
|
||||
nsIntRect compositionBounds = aFrameMetrics.mCompositionBounds;
|
||||
compositionBounds.ScaleInverseRoundIn(scale);
|
||||
const gfx::Rect& scrollableRect = aFrameMetrics.mScrollableRect;
|
||||
|
||||
gfx::Point scrollOffset = aFrameMetrics.mScrollOffset;
|
||||
|
||||
const float STATIONARY_SIZE_MULTIPLIER = 2.0f;
|
||||
gfx::Rect displayPort(0, 0,
|
||||
compositionBounds.width * STATIONARY_SIZE_MULTIPLIER,
|
||||
compositionBounds.height * STATIONARY_SIZE_MULTIPLIER);
|
||||
compositionBounds.width * X_STATIONARY_SIZE_MULTIPLIER,
|
||||
compositionBounds.height * Y_STATIONARY_SIZE_MULTIPLIER);
|
||||
|
||||
// If there's motion along an axis of movement, and it's above a threshold,
|
||||
// then we want to paint a larger area in the direction of that motion so that
|
||||
// it's less likely to checkerboard.
|
||||
bool enlargedX = EnlargeDisplayPortAlongAxis(
|
||||
compositionBounds.width, aVelocity.x, &displayPort.x, &displayPort.width);
|
||||
X_SKATE_SIZE_MULTIPLIER, estimatedPaintDuration,
|
||||
compositionBounds.width, aVelocity.x, aAcceleration.x,
|
||||
&displayPort.x, &displayPort.width);
|
||||
bool enlargedY = EnlargeDisplayPortAlongAxis(
|
||||
compositionBounds.height, aVelocity.y, &displayPort.y, &displayPort.height);
|
||||
Y_SKATE_SIZE_MULTIPLIER, estimatedPaintDuration,
|
||||
compositionBounds.height, aVelocity.y, aAcceleration.y,
|
||||
&displayPort.y, &displayPort.height);
|
||||
|
||||
if (!enlargedX && !enlargedY) {
|
||||
displayPort.x = -displayPort.width / 4;
|
||||
displayPort.y = -displayPort.height / 4;
|
||||
// Position the x and y such that the screen falls in the middle of the displayport.
|
||||
displayPort.x = -(displayPort.width - compositionBounds.width) / 2;
|
||||
displayPort.y = -(displayPort.height - compositionBounds.height) / 2;
|
||||
} else if (!enlargedX) {
|
||||
displayPort.width = compositionBounds.width;
|
||||
} else if (!enlargedY) {
|
||||
displayPort.height = compositionBounds.height;
|
||||
}
|
||||
|
||||
// If we go over the bounds when trying to predict where we will be when this
|
||||
// paint finishes, move it back into the range of the CSS content rect.
|
||||
// FIXME/bug 780395: Generalize this. This code is pretty hacky as it will
|
||||
// probably not work at all for RTL content. This is not intended to be
|
||||
// incredibly accurate; it'll just prevent the entire displayport from being
|
||||
// outside the content rect (which causes bad things to happen).
|
||||
if (enlargedX || enlargedY) {
|
||||
if (scrollOffset.x + compositionBounds.width > scrollableRect.width) {
|
||||
scrollOffset.x -= compositionBounds.width + scrollOffset.x - scrollableRect.width;
|
||||
} else if (scrollOffset.x < scrollableRect.x) {
|
||||
scrollOffset.x = scrollableRect.x;
|
||||
}
|
||||
if (scrollOffset.y + compositionBounds.height > scrollableRect.height) {
|
||||
scrollOffset.y -= compositionBounds.height + scrollOffset.y - scrollableRect.height;
|
||||
} else if (scrollOffset.y < scrollableRect.y) {
|
||||
scrollOffset.y = scrollableRect.y;
|
||||
}
|
||||
}
|
||||
|
||||
gfx::Rect shiftedDisplayPort = displayPort;
|
||||
shiftedDisplayPort.MoveBy(scrollOffset.x, scrollOffset.y);
|
||||
displayPort = shiftedDisplayPort.Intersect(aFrameMetrics.mScrollableRect);
|
||||
@ -797,8 +879,23 @@ void AsyncPanZoomController::ScheduleComposite() {
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::RequestContentRepaint() {
|
||||
mPreviousPaintStartTime = TimeStamp::Now();
|
||||
|
||||
double estimatedPaintSum = 0.0;
|
||||
for (uint32_t i = 0; i < mPreviousPaintDurations.Length(); i++) {
|
||||
estimatedPaintSum += mPreviousPaintDurations[i].ToSeconds();
|
||||
}
|
||||
|
||||
double estimatedPaintDuration = 0.0;
|
||||
if (estimatedPaintSum > EPSILON) {
|
||||
estimatedPaintDuration = estimatedPaintSum / mPreviousPaintDurations.Length();
|
||||
}
|
||||
|
||||
mFrameMetrics.mDisplayPort =
|
||||
CalculatePendingDisplayPort(mFrameMetrics, GetVelocityVector());
|
||||
CalculatePendingDisplayPort(mFrameMetrics,
|
||||
GetVelocityVector(),
|
||||
GetAccelerationVector(),
|
||||
estimatedPaintDuration);
|
||||
|
||||
gfx::Point oldScrollOffset = mLastPaintRequestMetrics.mScrollOffset,
|
||||
newScrollOffset = mFrameMetrics.mScrollOffset;
|
||||
@ -819,12 +916,27 @@ void AsyncPanZoomController::RequestContentRepaint() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Cache the resolution since we're temporarily changing it to accomodate
|
||||
// mixed resolution/zoom (normally we make them the same thing).
|
||||
float actualResolution = mFrameMetrics.mResolution.width;
|
||||
// Calculate the factor of acceleration based on the faster of the two axes.
|
||||
float accelerationFactor =
|
||||
clamped(NS_MAX(mX.GetAccelerationFactor(), mY.GetAccelerationFactor()),
|
||||
float(MIN_ZOOM) / 2.0f, float(MAX_ZOOM));
|
||||
// Scale down the resolution a bit based on acceleration.
|
||||
mFrameMetrics.mResolution.width = mFrameMetrics.mResolution.height =
|
||||
actualResolution / accelerationFactor;
|
||||
|
||||
// This message is compressed, so fire whether or not we already have a paint
|
||||
// queued up. We need to know whether or not a paint was requested anyways,
|
||||
// ofr the purposes of content calling window.scrollTo().
|
||||
mGeckoContentController->RequestContentRepaint(mFrameMetrics);
|
||||
mLastPaintRequestMetrics = mFrameMetrics;
|
||||
mWaitingForContentToPaint = true;
|
||||
|
||||
// Set the resolution back to what it was for the purpose of logic control.
|
||||
mFrameMetrics.mResolution.width = mFrameMetrics.mResolution.height =
|
||||
actualResolution;
|
||||
}
|
||||
|
||||
bool AsyncPanZoomController::SampleContentTransformForFrame(const TimeStamp& aSampleTime,
|
||||
@ -931,7 +1043,16 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aViewportFr
|
||||
|
||||
mLastContentPaintMetrics = aViewportFrame;
|
||||
|
||||
if (!mWaitingForContentToPaint) {
|
||||
if (mWaitingForContentToPaint) {
|
||||
// Remove the oldest sample we have if adding a new sample takes us over our
|
||||
// desired number of samples.
|
||||
if (mPreviousPaintDurations.Length() >= NUM_PAINT_DURATION_SAMPLES) {
|
||||
mPreviousPaintDurations.RemoveElementAt(0);
|
||||
}
|
||||
|
||||
mPreviousPaintDurations.AppendElement(
|
||||
TimeStamp::Now() - mPreviousPaintStartTime);
|
||||
} else {
|
||||
// No paint was requested, but we got one anyways. One possible cause of this
|
||||
// is that content could have fired a scrollTo(). In this case, we should take
|
||||
// the new scroll offset. Document/viewport changes are handled elsewhere.
|
||||
@ -954,6 +1075,8 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aViewportFr
|
||||
mWaitingForContentToPaint = false;
|
||||
|
||||
if (aIsFirstPaint || mFrameMetrics.IsDefault()) {
|
||||
mPreviousPaintDurations.Clear();
|
||||
|
||||
mX.CancelTouch();
|
||||
mY.CancelTouch();
|
||||
|
||||
|
@ -205,7 +205,9 @@ public:
|
||||
*/
|
||||
static const gfx::Rect CalculatePendingDisplayPort(
|
||||
const FrameMetrics& aFrameMetrics,
|
||||
const gfx::Point& aVelocity);
|
||||
const gfx::Point& aVelocity,
|
||||
const gfx::Point& aAcceleration,
|
||||
double aEstimatedPaintDuration);
|
||||
|
||||
protected:
|
||||
/**
|
||||
@ -333,6 +335,11 @@ protected:
|
||||
*/
|
||||
const gfx::Point GetVelocityVector();
|
||||
|
||||
/**
|
||||
* Gets a vector of the acceleration factors of each axis.
|
||||
*/
|
||||
const gfx::Point GetAccelerationVector();
|
||||
|
||||
/**
|
||||
* Gets a reference to the first SingleTouchData from a MultiTouchInput. This
|
||||
* gets only the first one and assumes the rest are either missing or not
|
||||
@ -365,8 +372,11 @@ protected:
|
||||
* |aDisplayPortLength|. If enlarged, these will be updated with the new
|
||||
* metrics.
|
||||
*/
|
||||
static bool EnlargeDisplayPortAlongAxis(float aCompositionBounds,
|
||||
static bool EnlargeDisplayPortAlongAxis(float aSkateSizeMultiplier,
|
||||
double aEstimatedPaintDuration,
|
||||
float aCompositionBounds,
|
||||
float aVelocity,
|
||||
float aAcceleration,
|
||||
float* aDisplayPortOffset,
|
||||
float* aDisplayPortLength);
|
||||
|
||||
@ -496,6 +506,13 @@ private:
|
||||
// |mMonitor|; that is, it should be held whenever this is updated.
|
||||
PanZoomState mState;
|
||||
|
||||
// How long it took in the past to paint after a series of previous requests.
|
||||
nsTArray<TimeDuration> mPreviousPaintDurations;
|
||||
|
||||
// When the last paint request started. Used to determine the duration of
|
||||
// previous paints.
|
||||
TimeStamp mPreviousPaintStartTime;
|
||||
|
||||
int mDPI;
|
||||
|
||||
// Stores the current paint status of the frame that we're managing. Repaints
|
||||
|
@ -18,7 +18,7 @@ static const float EPSILON = 0.0001f;
|
||||
* or we get a touch point very far away from the previous position for some
|
||||
* reason.
|
||||
*/
|
||||
static const float MAX_EVENT_ACCELERATION = 0.5f;
|
||||
static const float MAX_EVENT_ACCELERATION = 999.0f;
|
||||
|
||||
/**
|
||||
* Amount of friction applied during flings.
|
||||
@ -95,15 +95,19 @@ void Axis::StartTouch(int32_t aPos) {
|
||||
}
|
||||
|
||||
float Axis::GetDisplacementForDuration(float aScale, const TimeDuration& aDelta) {
|
||||
float velocityFactor = powf(ACCELERATION_MULTIPLIER,
|
||||
NS_MAX(0, (mAcceleration - 4) * 3));
|
||||
float displacement = mVelocity * aScale * aDelta.ToMilliseconds() * velocityFactor;
|
||||
if (fabsf(mVelocity) < VELOCITY_THRESHOLD) {
|
||||
mAcceleration = 0;
|
||||
}
|
||||
|
||||
float accelerationFactor = GetAccelerationFactor();
|
||||
float displacement = mVelocity * aScale * aDelta.ToMilliseconds() * accelerationFactor;
|
||||
// If this displacement will cause an overscroll, throttle it. Can potentially
|
||||
// bring it to 0 even if the velocity is high.
|
||||
if (DisplacementWillOverscroll(displacement) != OVERSCROLL_NONE) {
|
||||
// No need to have a velocity along this axis anymore; it won't take us
|
||||
// anywhere, so we're just spinning needlessly.
|
||||
mVelocity = 0.0f;
|
||||
mAcceleration = 0;
|
||||
displacement -= DisplacementWillOverscrollAmount(displacement);
|
||||
}
|
||||
return displacement;
|
||||
@ -231,6 +235,10 @@ float Axis::GetVelocity() {
|
||||
return mVelocity;
|
||||
}
|
||||
|
||||
float Axis::GetAccelerationFactor() {
|
||||
return powf(ACCELERATION_MULTIPLIER, NS_MAX(0, (mAcceleration - 4) * 3));
|
||||
}
|
||||
|
||||
float Axis::GetCompositionEnd() {
|
||||
return GetOrigin() + GetCompositionLength();
|
||||
}
|
||||
|
@ -116,6 +116,12 @@ public:
|
||||
*/
|
||||
float GetExcess();
|
||||
|
||||
/**
|
||||
* Gets the factor of acceleration applied to the velocity, based on the
|
||||
* amount of flings that have been done successively.
|
||||
*/
|
||||
float GetAccelerationFactor();
|
||||
|
||||
/**
|
||||
* Gets the raw velocity of this axis at this moment.
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user