Bug 912806 - Store both cumulative and non-cumulative resolutions in FrameMetrics and use whichever is appropriate. r=kats

This commit is contained in:
Botond Ballo 2013-09-05 18:26:59 -04:00
parent b4d4493dfd
commit 5fa50f4b24
8 changed files with 80 additions and 29 deletions

View File

@ -427,8 +427,11 @@ TabChild::Observe(nsISupports *aSubject,
mLastMetrics.mZoom = mLastMetrics.CalculateIntrinsicScale();
// We use ScreenToLayerScale(1) below in order to turn the
// async zoom amount into the gecko zoom amount.
mLastMetrics.mResolution =
mLastMetrics.mCumulativeResolution =
mLastMetrics.mZoom / mLastMetrics.mDevPixelsPerCSSPixel * ScreenToLayerScale(1);
// This is the root layer, so the cumulative resolution is the same
// as the resolution.
mLastMetrics.mResolution = mLastMetrics.mCumulativeResolution / LayoutDeviceToParentLayerScale(1);
mLastMetrics.mScrollOffset = CSSPoint(0, 0);
utils->SetResolution(mLastMetrics.mResolution.scale,
@ -692,7 +695,10 @@ TabChild::HandlePossibleViewportChange()
// 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);
metrics.mResolution = metrics.mZoom / metrics.mDevPixelsPerCSSPixel * ScreenToLayerScale(1);
metrics.mCumulativeResolution = metrics.mZoom / metrics.mDevPixelsPerCSSPixel * ScreenToLayerScale(1);
// This is the root layer, so the cumulative resolution is the same
// as the resolution.
metrics.mResolution = metrics.mCumulativeResolution / LayoutDeviceToParentLayerScale(1);
utils->SetResolution(metrics.mResolution.scale, metrics.mResolution.scale);
// Force a repaint with these metrics. This, among other things, sets the
@ -1616,8 +1622,10 @@ TabChild::ProcessUpdateFrame(const FrameMetrics& aFrameMetrics)
}
// set the resolution
LayoutDeviceToLayerScale resolution = aFrameMetrics.mZoom
/ aFrameMetrics.mDevPixelsPerCSSPixel * ScreenToLayerScale(1);
ParentLayerToLayerScale resolution = aFrameMetrics.mZoom
/ aFrameMetrics.mDevPixelsPerCSSPixel
/ aFrameMetrics.GetParentResolution()
* ScreenToLayerScale(1);
utils->SetResolution(resolution.scale, resolution.scale);
// and set the display port

View File

@ -576,6 +576,7 @@ struct ParamTraits<mozilla::layers::FrameMetrics>
WriteParam(aMsg, aParam.mCompositionBounds);
WriteParam(aMsg, aParam.mScrollId);
WriteParam(aMsg, aParam.mResolution);
WriteParam(aMsg, aParam.mCumulativeResolution);
WriteParam(aMsg, aParam.mZoom);
WriteParam(aMsg, aParam.mDevPixelsPerCSSPixel);
WriteParam(aMsg, aParam.mMayHaveTouchListeners);
@ -592,6 +593,7 @@ struct ParamTraits<mozilla::layers::FrameMetrics>
ReadParam(aMsg, aIter, &aResult->mCompositionBounds) &&
ReadParam(aMsg, aIter, &aResult->mScrollId) &&
ReadParam(aMsg, aIter, &aResult->mResolution) &&
ReadParam(aMsg, aIter, &aResult->mCumulativeResolution) &&
ReadParam(aMsg, aIter, &aResult->mZoom) &&
ReadParam(aMsg, aIter, &aResult->mDevPixelsPerCSSPixel) &&
ReadParam(aMsg, aIter, &aResult->mMayHaveTouchListeners) &&

View File

@ -15,6 +15,16 @@
namespace mozilla {
namespace layers {
// The layer coordinates of the parent layer. Like the layer coordinates
// of the current layer (LayerPixel) but doesn't include the current layer's
// resolution.
struct ParentLayerPixel {};
typedef gfx::ScaleFactor<LayoutDevicePixel, ParentLayerPixel> LayoutDeviceToParentLayerScale;
typedef gfx::ScaleFactor<ParentLayerPixel, LayerPixel> ParentLayerToLayerScale;
typedef gfx::ScaleFactor<ParentLayerPixel, ScreenPixel> ParentLayerToScreenScale;
/**
* The viewport and displayport metrics for the painted frame at the
* time of a layer-tree transaction. These metrics are especially
@ -39,6 +49,7 @@ public:
, mScrollId(NULL_SCROLL_ID)
, mScrollableRect(0, 0, 0, 0)
, mResolution(1)
, mCumulativeResolution(1)
, mZoom(1)
, mDevPixelsPerCSSPixel(1)
, mMayHaveTouchListeners(false)
@ -57,6 +68,7 @@ public:
mScrollId == aOther.mScrollId &&
mScrollableRect.IsEqualEdges(aOther.mScrollableRect) &&
mResolution == aOther.mResolution &&
mCumulativeResolution == aOther.mCumulativeResolution &&
mDevPixelsPerCSSPixel == aOther.mDevPixelsPerCSSPixel &&
mMayHaveTouchListeners == aOther.mMayHaveTouchListeners &&
mPresShellId == aOther.mPresShellId;
@ -86,7 +98,7 @@ public:
CSSToLayerScale LayersPixelsPerCSSPixel() const
{
return mResolution * mDevPixelsPerCSSPixel;
return mCumulativeResolution * mDevPixelsPerCSSPixel;
}
LayerPoint GetScrollOffsetInLayerPixels() const
@ -94,6 +106,11 @@ public:
return mScrollOffset * LayersPixelsPerCSSPixel();
}
LayoutDeviceToParentLayerScale GetParentResolution() const
{
return mCumulativeResolution / mResolution;
}
/**
* Return the scale factor needed to fit the viewport
* into its composition bounds.
@ -211,15 +228,18 @@ public:
// The following metrics are dimensionless.
//
// The resolution, along both axes, that the current frame has been painted
// at.
// The resolution that the current frame has been painted at.
//
// Every time this frame is composited and the compositor samples its
// transform, this metric is used to create a transform which is
// post-multiplied into the parent's transform. Since this only happens when
// we walk the layer tree, the resulting transform isn't stored here. Thus the
// resolution of parent layers is opaque to this metric.
LayoutDeviceToLayerScale mResolution;
ParentLayerToLayerScale mResolution;
// The cumulative resolution that the current frame has been painted at.
// This is the product of our mResolution and the mResolutions of our parent frames.
LayoutDeviceToLayerScale mCumulativeResolution;
// The "user zoom". Content is painted by gecko at mResolution * mDevPixelsPerCSSPixel,
// but will be drawn to the screen at mZoom. In the steady state, the

View File

@ -497,7 +497,7 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(TimeStamp aCurrentFram
LayoutDeviceToLayerScale resolution(1.0 / rootTransform.GetXScale(),
1.0 / rootTransform.GetYScale());
#else
LayoutDeviceToLayerScale resolution = metrics.mResolution;
LayoutDeviceToLayerScale resolution = metrics.mCumulativeResolution;
#endif
oldTransform.Scale(resolution.scale, resolution.scale, 1);
@ -556,7 +556,7 @@ AsyncCompositionManager::TransformScrollableLayer(Layer* aLayer, const LayoutDev
// appears to be that metrics.mZoom is poorly initialized in some scenarios. In these scenarios,
// however, we can assume there is no async zooming in progress and so the following statement
// works fine.
CSSToScreenScale userZoom(metrics.mDevPixelsPerCSSPixel.scale * metrics.mResolution.scale);
CSSToScreenScale userZoom(metrics.mDevPixelsPerCSSPixel * metrics.mCumulativeResolution * LayerToScreenScale(1));
ScreenPoint userScroll = metrics.mScrollOffset * userZoom;
SyncViewportInfo(displayPort, geckoZoom, mLayersUpdated,
userScroll, userZoom, fixedLayerMargins,
@ -580,7 +580,10 @@ AsyncCompositionManager::TransformScrollableLayer(Layer* aLayer, const LayoutDev
}
LayerPoint translation = (userScroll / zoomAdjust) - geckoScroll;
treeTransform = gfx3DMatrix(ViewTransform(-translation, userZoom / metrics.mDevPixelsPerCSSPixel));
treeTransform = gfx3DMatrix(ViewTransform(-translation,
userZoom
/ metrics.mDevPixelsPerCSSPixel
/ metrics.GetParentResolution()));
// The transform already takes the resolution scale into account. Since we
// will apply the resolution scale again when computing the effective
@ -680,7 +683,7 @@ AsyncCompositionManager::TransformShadowTree(TimeStamp aCurrentFrame)
1.0 / rootTransform.GetYScale());
#else
LayoutDeviceToLayerScale resolution =
scrollableLayers[i]->AsContainerLayer()->GetFrameMetrics().mResolution;
scrollableLayers[i]->AsContainerLayer()->GetFrameMetrics().mCumulativeResolution;
#endif
TransformScrollableLayer(scrollableLayers[i], resolution);
}

View File

@ -30,7 +30,7 @@ class AutoResolveRefLayers;
// Represents (affine) transforms that are calculated from a content view.
struct ViewTransform {
ViewTransform(LayerPoint aTranslation = LayerPoint(),
LayoutDeviceToScreenScale aScale = LayoutDeviceToScreenScale())
ParentLayerToScreenScale aScale = ParentLayerToScreenScale())
: mTranslation(aTranslation)
, mScale(aScale)
{}
@ -51,7 +51,7 @@ struct ViewTransform {
}
LayerPoint mTranslation;
LayoutDeviceToScreenScale mScale;
ParentLayerToScreenScale mScale;
};
/**

View File

@ -963,7 +963,7 @@ void AsyncPanZoomController::RequestContentRepaint() {
mFrameMetrics.mScrollOffset.x) < EPSILON &&
fabsf(mLastPaintRequestMetrics.mScrollOffset.y -
mFrameMetrics.mScrollOffset.y) < EPSILON &&
mFrameMetrics.mResolution == mLastPaintRequestMetrics.mResolution) {
mFrameMetrics.mCumulativeResolution == mLastPaintRequestMetrics.mCumulativeResolution) {
return;
}
@ -1110,8 +1110,11 @@ ViewTransform AsyncPanZoomController::GetCurrentAsyncTransform() {
}
LayerPoint translation = (mFrameMetrics.mScrollOffset - lastPaintScrollOffset)
* mLastContentPaintMetrics.LayersPixelsPerCSSPixel();
return ViewTransform(-translation,
mFrameMetrics.mZoom / mLastContentPaintMetrics.mDevPixelsPerCSSPixel);
mFrameMetrics.mZoom
/ mLastContentPaintMetrics.mDevPixelsPerCSSPixel
/ mFrameMetrics.GetParentResolution());
}
void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aLayerMetrics, bool aIsFirstPaint) {
@ -1347,11 +1350,14 @@ void AsyncPanZoomController::TimeoutTouchListeners() {
void AsyncPanZoomController::SetZoomAndResolution(const CSSToScreenScale& aZoom) {
mMonitor.AssertCurrentThreadIn();
LayoutDeviceToParentLayerScale parentResolution = mFrameMetrics.GetParentResolution();
mFrameMetrics.mZoom = aZoom;
// We use ScreenToLayerScale(1) below in order to ask gecko to render
// what's currently visible on the screen. This is effectively turning
// the async zoom amount into the gecko zoom amount.
mFrameMetrics.mResolution = aZoom / mFrameMetrics.mDevPixelsPerCSSPixel * ScreenToLayerScale(1);
mFrameMetrics.mCumulativeResolution = aZoom / mFrameMetrics.mDevPixelsPerCSSPixel * ScreenToLayerScale(1);
// The parent resolution will not have changed.
mFrameMetrics.mResolution = mFrameMetrics.mCumulativeResolution / parentResolution;
}
void AsyncPanZoomController::UpdateZoomConstraints(bool aAllowZoom,

View File

@ -177,7 +177,8 @@ TEST(AsyncPanZoomController, ComplexTransform) {
metrics.mViewport = CSSRect(0, 0, 4, 4);
metrics.mScrollOffset = CSSPoint(10, 10);
metrics.mScrollableRect = CSSRect(0, 0, 50, 50);
metrics.mResolution = LayoutDeviceToLayerScale(2);
metrics.mCumulativeResolution = LayoutDeviceToLayerScale(2);
metrics.mResolution = ParentLayerToLayerScale(2);
metrics.mZoom = CSSToScreenScale(6);
metrics.mDevPixelsPerCSSPixel = CSSToLayoutDeviceScale(3);
metrics.mScrollId = FrameMetrics::ROOT_SCROLL_ID;
@ -198,39 +199,39 @@ TEST(AsyncPanZoomController, ComplexTransform) {
apzc->SetFrameMetrics(metrics);
apzc->NotifyLayersUpdated(metrics, true);
apzc->SampleContentTransformForFrame(testStartTime, &viewTransformOut, pointOut);
EXPECT_EQ(ViewTransform(LayerPoint(), LayoutDeviceToScreenScale(2)), viewTransformOut);
EXPECT_EQ(ViewTransform(LayerPoint(), ParentLayerToScreenScale(2)), viewTransformOut);
EXPECT_EQ(ScreenPoint(60, 60), pointOut);
childApzc->SetFrameMetrics(childMetrics);
childApzc->NotifyLayersUpdated(childMetrics, true);
childApzc->SampleContentTransformForFrame(testStartTime, &viewTransformOut, pointOut);
EXPECT_EQ(ViewTransform(LayerPoint(), LayoutDeviceToScreenScale(2)), viewTransformOut);
EXPECT_EQ(ViewTransform(LayerPoint(), ParentLayerToScreenScale(2)), viewTransformOut);
EXPECT_EQ(ScreenPoint(60, 60), pointOut);
// do an async scroll by 5 pixels and check the transform
metrics.mScrollOffset += CSSPoint(5, 0);
apzc->SetFrameMetrics(metrics);
apzc->SampleContentTransformForFrame(testStartTime, &viewTransformOut, pointOut);
EXPECT_EQ(ViewTransform(LayerPoint(-30, 0), LayoutDeviceToScreenScale(2)), viewTransformOut);
EXPECT_EQ(ViewTransform(LayerPoint(-30, 0), ParentLayerToScreenScale(2)), viewTransformOut);
EXPECT_EQ(ScreenPoint(90, 60), pointOut);
childMetrics.mScrollOffset += CSSPoint(5, 0);
childApzc->SetFrameMetrics(childMetrics);
childApzc->SampleContentTransformForFrame(testStartTime, &viewTransformOut, pointOut);
EXPECT_EQ(ViewTransform(LayerPoint(-30, 0), LayoutDeviceToScreenScale(2)), viewTransformOut);
EXPECT_EQ(ViewTransform(LayerPoint(-30, 0), ParentLayerToScreenScale(2)), viewTransformOut);
EXPECT_EQ(ScreenPoint(90, 60), pointOut);
// do an async zoom of 1.5x and check the transform
metrics.mZoom.scale *= 1.5f;
apzc->SetFrameMetrics(metrics);
apzc->SampleContentTransformForFrame(testStartTime, &viewTransformOut, pointOut);
EXPECT_EQ(ViewTransform(LayerPoint(-30, 0), LayoutDeviceToScreenScale(3)), viewTransformOut);
EXPECT_EQ(ViewTransform(LayerPoint(-30, 0), ParentLayerToScreenScale(3)), viewTransformOut);
EXPECT_EQ(ScreenPoint(135, 90), pointOut);
childMetrics.mZoom.scale *= 1.5f;
childApzc->SetFrameMetrics(childMetrics);
childApzc->SampleContentTransformForFrame(testStartTime, &viewTransformOut, pointOut);
EXPECT_EQ(ViewTransform(LayerPoint(-30, 0), LayoutDeviceToScreenScale(3)), viewTransformOut);
EXPECT_EQ(ViewTransform(LayerPoint(-30, 0), ParentLayerToScreenScale(3)), viewTransformOut);
EXPECT_EQ(ScreenPoint(135, 90), pointOut);
}

View File

@ -663,20 +663,31 @@ static void RecordFrameMetrics(nsIFrame* aForFrame,
nsIPresShell* presShell = presContext->GetPresShell();
if (metrics.mScrollId == FrameMetrics::ROOT_SCROLL_ID) {
metrics.mResolution = LayoutDeviceToLayerScale(presShell->GetXResolution(),
presShell->GetYResolution());
metrics.mResolution = ParentLayerToLayerScale(presShell->GetXResolution(),
presShell->GetYResolution());
} else {
// Only the root scrollable frame for a given presShell should pick up
// the presShell's resolution. All the other subframes are 1.0.
metrics.mResolution = LayoutDeviceToLayerScale(1.0f);
metrics.mResolution = ParentLayerToLayerScale(1.0f);
}
metrics.mCumulativeResolution = LayoutDeviceToLayerScale(1.0f);
nsIPresShell* curPresShell = presShell;
while (curPresShell != nullptr) {
ParentLayerToLayerScale presShellResolution(curPresShell->GetXResolution(),
curPresShell->GetYResolution());
metrics.mCumulativeResolution.scale *= presShellResolution.scale;
nsPresContext* parentContext = curPresShell->GetPresContext()->GetParentPresContext();
curPresShell = parentContext ? parentContext->GetPresShell() : nullptr;
}
metrics.mDevPixelsPerCSSPixel = CSSToLayoutDeviceScale(
(float)nsPresContext::AppUnitsPerCSSPixel() / auPerDevPixel);
// Initially, AsyncPanZoomController should render the content to the screen
// at the painted resolution.
const LayerToScreenScale layerToScreenScale(1.0f);
metrics.mZoom = metrics.mResolution * metrics.mDevPixelsPerCSSPixel
metrics.mZoom = metrics.mCumulativeResolution * metrics.mDevPixelsPerCSSPixel
* layerToScreenScale;
metrics.mMayHaveTouchListeners = aMayHaveTouchListeners;
@ -689,7 +700,7 @@ static void RecordFrameMetrics(nsIFrame* aForFrame,
nsRect compositionBounds(frameForCompositionBoundsCalculation->GetOffsetToCrossDoc(aReferenceFrame),
frameForCompositionBoundsCalculation->GetSize());
metrics.mCompositionBounds = RoundedToInt(LayoutDeviceRect::FromAppUnits(compositionBounds, auPerDevPixel)
* metrics.mResolution
* metrics.mCumulativeResolution
* layerToScreenScale);
// Adjust composition bounds for the size of scroll bars.