Bug 818575 - Make TransformShadowTree transform all descendant scrollable layers instead of just the first. r=roc a=blocking-basecamp

This commit is contained in:
Matt Woodrow 2013-01-10 22:10:20 +13:00
Родитель 8e4ca058c8
Коммит a84a375464
4 изменённых файлов: 163 добавлений и 108 удалений

Просмотреть файл

@ -229,6 +229,36 @@ LayerManager::GetPrimaryScrollableLayer()
return mRoot;
}
void
LayerManager::GetScrollableLayers(nsTArray<Layer*>& aArray)
{
if (!mRoot) {
return;
}
nsTArray<Layer*> queue;
queue.AppendElement(mRoot);
while (!queue.IsEmpty()) {
ContainerLayer* containerLayer = queue.LastElement()->AsContainerLayer();
queue.RemoveElementAt(queue.Length() - 1);
if (!containerLayer) {
continue;
}
const FrameMetrics& frameMetrics = containerLayer->GetFrameMetrics();
if (frameMetrics.IsScrollable()) {
aArray.AppendElement(containerLayer);
continue;
}
Layer* child = containerLayer->GetFirstChild();
while (child) {
queue.AppendElement(child);
child = child->GetNextSibling();
}
}
}
already_AddRefed<gfxASurface>
LayerManager::CreateOptimalSurface(const gfxIntSize &aSize,
gfxASurface::gfxImageFormat aFormat)

Просмотреть файл

@ -285,6 +285,12 @@ public:
*/
Layer* GetPrimaryScrollableLayer();
/**
* Returns a list of all descendant layers for which
* GetFrameMetrics().IsScrollable() is true.
*/
void GetScrollableLayers(nsTArray<Layer*>& aArray);
/**
* CONSTRUCTION PHASE ONLY
* Called when a managee has mutated.

Просмотреть файл

@ -829,24 +829,133 @@ CompositorParent::ApplyAsyncContentTransformToTree(TimeStamp aCurrentFrame,
return appliedTransform;
}
void
CompositorParent::TransformScrollableLayer(Layer* aLayer, const gfx3DMatrix& aRootTransform)
{
ShadowLayer* shadow = aLayer->AsShadowLayer();
ContainerLayer* container = aLayer->AsContainerLayer();
const FrameMetrics& metrics = container->GetFrameMetrics();
// We must apply the resolution scale before a pan/zoom transform, so we call
// GetTransform here.
const gfx3DMatrix& currentTransform = aLayer->GetTransform();
gfx3DMatrix treeTransform;
// Translate fixed position layers so that they stay in the correct position
// when mScrollOffset and metricsScrollOffset differ.
gfxPoint offset;
gfxPoint scaleDiff;
float rootScaleX = aRootTransform.GetXScale(),
rootScaleY = aRootTransform.GetYScale();
// The ratio of layers pixels to device pixels. The Java
// compositor wants to see values in units of device pixels, so we
// map our FrameMetrics values to that space. This is not exposed
// as a FrameMetrics helper because it's a deprecated conversion.
float devPixelRatioX = 1 / rootScaleX, devPixelRatioY = 1 / rootScaleY;
gfx::Point scrollOffsetLayersPixels(metrics.GetScrollOffsetInLayerPixels());
nsIntPoint scrollOffsetDevPixels(
NS_lround(scrollOffsetLayersPixels.x * devPixelRatioX),
NS_lround(scrollOffsetLayersPixels.y * devPixelRatioY));
if (mIsFirstPaint) {
mContentRect = metrics.mContentRect;
SetFirstPaintViewport(scrollOffsetDevPixels,
1/rootScaleX,
mContentRect,
metrics.mScrollableRect);
mIsFirstPaint = false;
} else if (!metrics.mContentRect.IsEqualEdges(mContentRect)) {
mContentRect = metrics.mContentRect;
SetPageRect(metrics.mScrollableRect);
}
// We synchronise the viewport information with Java after sending the above
// notifications, so that Java can take these into account in its response.
// Calculate the absolute display port to send to Java
gfx::Rect displayPortLayersPixels(metrics.mDisplayPort);
nsIntRect displayPortDevPixels(
NS_lround(displayPortLayersPixels.x * devPixelRatioX),
NS_lround(displayPortLayersPixels.y * devPixelRatioY),
NS_lround(displayPortLayersPixels.width * devPixelRatioX),
NS_lround(displayPortLayersPixels.height * devPixelRatioY));
displayPortDevPixels.x += scrollOffsetDevPixels.x;
displayPortDevPixels.y += scrollOffsetDevPixels.y;
SyncViewportInfo(displayPortDevPixels, 1/rootScaleX, mLayersUpdated,
mScrollOffset, mXScale, mYScale);
mLayersUpdated = false;
// Handle transformations for asynchronous panning and zooming. We determine the
// zoom used by Gecko from the transformation set on the root layer, and we
// determine the scroll offset used by Gecko from the frame metrics of the
// primary scrollable layer. We compare this to the desired zoom and scroll
// offset in the view transform we obtained from Java in order to compute the
// transformation we need to apply.
float tempScaleDiffX = rootScaleX * mXScale;
float tempScaleDiffY = rootScaleY * mYScale;
nsIntPoint metricsScrollOffset(0, 0);
if (metrics.IsScrollable()) {
metricsScrollOffset = scrollOffsetDevPixels;
}
nsIntPoint scrollCompensation(
(mScrollOffset.x / tempScaleDiffX - metricsScrollOffset.x) * mXScale,
(mScrollOffset.y / tempScaleDiffY - metricsScrollOffset.y) * mYScale);
treeTransform = gfx3DMatrix(ViewTransform(-scrollCompensation, mXScale, mYScale));
// If the contents can fit entirely within the widget area on a particular
// dimenson, we need to translate and scale so that the fixed layers remain
// within the page boundaries.
if (mContentRect.width * tempScaleDiffX < mWidgetSize.width) {
offset.x = -metricsScrollOffset.x;
scaleDiff.x = NS_MIN(1.0f, mWidgetSize.width / (float)mContentRect.width);
} else {
offset.x = clamped(mScrollOffset.x / tempScaleDiffX, (float)mContentRect.x,
mContentRect.XMost() - mWidgetSize.width / tempScaleDiffX) -
metricsScrollOffset.x;
scaleDiff.x = tempScaleDiffX;
}
if (mContentRect.height * tempScaleDiffY < mWidgetSize.height) {
offset.y = -metricsScrollOffset.y;
scaleDiff.y = NS_MIN(1.0f, mWidgetSize.height / (float)mContentRect.height);
} else {
offset.y = clamped(mScrollOffset.y / tempScaleDiffY, (float)mContentRect.y,
mContentRect.YMost() - mWidgetSize.height / tempScaleDiffY) -
metricsScrollOffset.y;
scaleDiff.y = tempScaleDiffY;
}
// The transform already takes the resolution scale into account. Since we
// will apply the resolution scale again when computing the effective
// transform, we must apply the inverse resolution scale here.
gfx3DMatrix computedTransform = treeTransform * currentTransform;
computedTransform.Scale(1.0f/container->GetPreXScale(),
1.0f/container->GetPreYScale(),
1);
computedTransform.ScalePost(1.0f/container->GetPostXScale(),
1.0f/container->GetPostYScale(),
1);
shadow->SetShadowTransform(computedTransform);
TransformFixedLayers(aLayer, offset, scaleDiff);
}
bool
CompositorParent::TransformShadowTree(TimeStamp aCurrentFrame)
{
bool wantNextFrame = false;
Layer* layer = mLayerManager->GetPrimaryScrollableLayer();
ShadowLayer* shadow = layer->AsShadowLayer();
ContainerLayer* container = layer->AsContainerLayer();
Layer* root = mLayerManager->GetRoot();
// NB: we must sample animations *before* sampling pan/zoom
// transforms.
wantNextFrame |= SampleAnimations(root, aCurrentFrame);
const FrameMetrics& metrics = container->GetFrameMetrics();
// We must apply the resolution scale before a pan/zoom transform, so we call
// GetTransform here.
const gfx3DMatrix& rootTransform = root->GetTransform();
const gfx3DMatrix& currentTransform = layer->GetTransform();
// FIXME/bug 775437: unify this interface with the ~native-fennec
// derived code
@ -860,109 +969,18 @@ CompositorParent::TransformShadowTree(TimeStamp aCurrentFrame)
// its own platform-specific async rendering that is done partially
// in Gecko and partially in Java.
if (!ApplyAsyncContentTransformToTree(aCurrentFrame, root, &wantNextFrame)) {
gfx3DMatrix treeTransform;
nsAutoTArray<Layer*,1> scrollableLayers;
#ifdef MOZ_WIDGET_ANDROID
scrollableLayers.AppendElement(mLayerManager->GetPrimaryScrollableLayer());
#else
mLayerManager->GetScrollableLayers(scrollableLayers);
#endif
// Translate fixed position layers so that they stay in the correct position
// when mScrollOffset and metricsScrollOffset differ.
gfxPoint offset;
gfxPoint scaleDiff;
float rootScaleX = rootTransform.GetXScale(),
rootScaleY = rootTransform.GetYScale();
// The ratio of layers pixels to device pixels. The Java
// compositor wants to see values in units of device pixels, so we
// map our FrameMetrics values to that space. This is not exposed
// as a FrameMetrics helper because it's a deprecated conversion.
float devPixelRatioX = 1 / rootScaleX, devPixelRatioY = 1 / rootScaleY;
gfx::Point scrollOffsetLayersPixels(metrics.GetScrollOffsetInLayerPixels());
nsIntPoint scrollOffsetDevPixels(
NS_lround(scrollOffsetLayersPixels.x * devPixelRatioX),
NS_lround(scrollOffsetLayersPixels.y * devPixelRatioY));
if (mIsFirstPaint) {
mContentRect = metrics.mContentRect;
SetFirstPaintViewport(scrollOffsetDevPixels,
1/rootScaleX,
mContentRect,
metrics.mScrollableRect);
mIsFirstPaint = false;
} else if (!metrics.mContentRect.IsEqualEdges(mContentRect)) {
mContentRect = metrics.mContentRect;
SetPageRect(metrics.mScrollableRect);
for (uint32_t i = 0; i < scrollableLayers.Length(); i++) {
if (scrollableLayers[i]) {
TransformScrollableLayer(scrollableLayers[i], rootTransform);
}
}
// We synchronise the viewport information with Java after sending the above
// notifications, so that Java can take these into account in its response.
// Calculate the absolute display port to send to Java
gfx::Rect displayPortLayersPixels(metrics.mDisplayPort);
nsIntRect displayPortDevPixels(
NS_lround(displayPortLayersPixels.x * devPixelRatioX),
NS_lround(displayPortLayersPixels.y * devPixelRatioY),
NS_lround(displayPortLayersPixels.width * devPixelRatioX),
NS_lround(displayPortLayersPixels.height * devPixelRatioY));
displayPortDevPixels.x += scrollOffsetDevPixels.x;
displayPortDevPixels.y += scrollOffsetDevPixels.y;
SyncViewportInfo(displayPortDevPixels, 1/rootScaleX, mLayersUpdated,
mScrollOffset, mXScale, mYScale);
mLayersUpdated = false;
// Handle transformations for asynchronous panning and zooming. We determine the
// zoom used by Gecko from the transformation set on the root layer, and we
// determine the scroll offset used by Gecko from the frame metrics of the
// primary scrollable layer. We compare this to the desired zoom and scroll
// offset in the view transform we obtained from Java in order to compute the
// transformation we need to apply.
float tempScaleDiffX = rootScaleX * mXScale;
float tempScaleDiffY = rootScaleY * mYScale;
nsIntPoint metricsScrollOffset(0, 0);
if (metrics.IsScrollable()) {
metricsScrollOffset = scrollOffsetDevPixels;
}
nsIntPoint scrollCompensation(
(mScrollOffset.x / tempScaleDiffX - metricsScrollOffset.x) * mXScale,
(mScrollOffset.y / tempScaleDiffY - metricsScrollOffset.y) * mYScale);
treeTransform = gfx3DMatrix(ViewTransform(-scrollCompensation, mXScale, mYScale));
// If the contents can fit entirely within the widget area on a particular
// dimenson, we need to translate and scale so that the fixed layers remain
// within the page boundaries.
if (mContentRect.width * tempScaleDiffX < mWidgetSize.width) {
offset.x = -metricsScrollOffset.x;
scaleDiff.x = NS_MIN(1.0f, mWidgetSize.width / (float)mContentRect.width);
} else {
offset.x = clamped(mScrollOffset.x / tempScaleDiffX, (float)mContentRect.x,
mContentRect.XMost() - mWidgetSize.width / tempScaleDiffX) -
metricsScrollOffset.x;
scaleDiff.x = tempScaleDiffX;
}
if (mContentRect.height * tempScaleDiffY < mWidgetSize.height) {
offset.y = -metricsScrollOffset.y;
scaleDiff.y = NS_MIN(1.0f, mWidgetSize.height / (float)mContentRect.height);
} else {
offset.y = clamped(mScrollOffset.y / tempScaleDiffY, (float)mContentRect.y,
mContentRect.YMost() - mWidgetSize.height / tempScaleDiffY) -
metricsScrollOffset.y;
scaleDiff.y = tempScaleDiffY;
}
// The transform already takes the resolution scale into account. Since we
// will apply the resolution scale again when computing the effective
// transform, we must apply the inverse resolution scale here.
gfx3DMatrix computedTransform = treeTransform * currentTransform;
computedTransform.Scale(1.0f/container->GetPreXScale(),
1.0f/container->GetPreYScale(),
1);
computedTransform.ScalePost(1.0f/container->GetPostXScale(),
1.0f/container->GetPostYScale(),
1);
shadow->SetShadowTransform(computedTransform);
TransformFixedLayers(layer, offset, scaleDiff);
}
return wantNextFrame;

Просмотреть файл

@ -176,6 +176,7 @@ private:
// Sample transforms for layer trees. Return true to request
// another animation frame.
bool TransformShadowTree(TimeStamp aCurrentFrame);
void TransformScrollableLayer(Layer* aLayer, const gfx3DMatrix& aRootTransform);
// Return true if an AsyncPanZoomController content transform was
// applied for |aLayer|. *aWantNextFrame is set to true if the
// controller wants another animation frame.