author | Matt Woodrow <mwoodrow@mozilla.com> |
Thu, 10 Jan 2013 22:10:20 +1300 | |
changeset 118499 | 7d0aa0231e3778d2d4bf79c6d3244b8757eced74 |
parent 118498 | fa88bbeed9b1f8160c46ea7c64d97eb89b42746d |
child 118500 | 0831c937f066b2eb9631d99b06afb6cfc5169002 |
push id | 24166 |
push user | Ms2ger@gmail.com |
push date | Fri, 11 Jan 2013 13:57:41 +0000 |
treeherder | mozilla-central@63c4b0f66a0c [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | roc |
bugs | 818575 |
milestone | 21.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/gfx/layers/Layers.cpp +++ b/gfx/layers/Layers.cpp @@ -225,16 +225,46 @@ LayerManager::GetPrimaryScrollableLayer( queue.AppendElement(child); child = child->GetNextSibling(); } } 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) { return gfxPlatform::GetPlatform()-> CreateOffscreenSurface(aSize, gfxASurface::ContentFromFormat(aFormat)); }
--- a/gfx/layers/Layers.h +++ b/gfx/layers/Layers.h @@ -283,16 +283,22 @@ public: /** * Does a breadth-first search from the root layer to find the first * scrollable layer. * Can be called any time. */ 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. * Subclasses overriding this method must first call their * superclass's impl */ #ifdef DEBUG // In debug builds, we check some properties of |aLayer|. virtual void Mutated(Layer* aLayer);
--- a/gfx/layers/ipc/CompositorParent.cpp +++ b/gfx/layers/ipc/CompositorParent.cpp @@ -892,152 +892,170 @@ CompositorParent::ApplyAsyncContentTrans treeTransform.mScale); appliedTransform = true; } 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; + gfxSize 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; + + gfxPoint 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.mCriticalDisplayPort.IsEmpty() ? + metrics.mDisplayPort : metrics.mCriticalDisplayPort); + 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, + gfxSize(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 < metrics.mCompositionBounds.width) { + offset.x = -metricsScrollOffset.x; + scaleDiff.width = NS_MIN(1.0f, metrics.mCompositionBounds.width / (float)mContentRect.width); + } else { + offset.x = clamped(mScrollOffset.x / tempScaleDiffX, (float)mContentRect.x, + mContentRect.XMost() - metrics.mCompositionBounds.width / tempScaleDiffX) - + metricsScrollOffset.x; + scaleDiff.width = tempScaleDiffX; + } + + if (mContentRect.height * tempScaleDiffY < metrics.mCompositionBounds.height) { + offset.y = -metricsScrollOffset.y; + scaleDiff.height = NS_MIN(1.0f, metrics.mCompositionBounds.height / (float)mContentRect.height); + } else { + offset.y = clamped(mScrollOffset.y / tempScaleDiffY, (float)mContentRect.y, + mContentRect.YMost() - metrics.mCompositionBounds.height / tempScaleDiffY) - + metricsScrollOffset.y; + scaleDiff.height = 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 // // Attempt to apply an async content transform to any layer that has // an async pan zoom controller (which means that it is rendered // async using Gecko). If this fails, fall back to transforming the // primary scrollable layer. "Failing" here means that we don't // find a frame that is async scrollable. Note that the fallback // code also includes Fennec which is rendered async. Fennec uses // its own platform-specific async rendering that is done partially // in Gecko and partially in Java. if (!ApplyAsyncContentTransformToTree(aCurrentFrame, root, &wantNextFrame)) { - gfx3DMatrix treeTransform; - - // Translate fixed position layers so that they stay in the correct position - // when mScrollOffset and metricsScrollOffset differ. - gfxPoint offset; - gfxSize 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; - - gfxPoint 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.mCriticalDisplayPort.IsEmpty() ? - metrics.mDisplayPort : metrics.mCriticalDisplayPort); - 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; + nsAutoTArray<Layer*,1> scrollableLayers; +#ifdef MOZ_WIDGET_ANDROID + scrollableLayers.AppendElement(mLayerManager->GetPrimaryScrollableLayer()); +#else + mLayerManager->GetScrollableLayers(scrollableLayers); +#endif - // 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; + for (uint32_t i = 0; i < scrollableLayers.Length(); i++) { + if (scrollableLayers[i]) { + TransformScrollableLayer(scrollableLayers[i], rootTransform); + } } - - nsIntPoint scrollCompensation( - (mScrollOffset.x / tempScaleDiffX - metricsScrollOffset.x) * mXScale, - (mScrollOffset.y / tempScaleDiffY - metricsScrollOffset.y) * mYScale); - treeTransform = gfx3DMatrix(ViewTransform(-scrollCompensation, - gfxSize(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 < metrics.mCompositionBounds.width) { - offset.x = -metricsScrollOffset.x; - scaleDiff.width = NS_MIN(1.0f, metrics.mCompositionBounds.width / (float)mContentRect.width); - } else { - offset.x = clamped(mScrollOffset.x / tempScaleDiffX, (float)mContentRect.x, - mContentRect.XMost() - metrics.mCompositionBounds.width / tempScaleDiffX) - - metricsScrollOffset.x; - scaleDiff.width = tempScaleDiffX; - } - - if (mContentRect.height * tempScaleDiffY < metrics.mCompositionBounds.height) { - offset.y = -metricsScrollOffset.y; - scaleDiff.height = NS_MIN(1.0f, metrics.mCompositionBounds.height / (float)mContentRect.height); - } else { - offset.y = clamped(mScrollOffset.y / tempScaleDiffY, (float)mContentRect.y, - mContentRect.YMost() - metrics.mCompositionBounds.height / tempScaleDiffY) - - metricsScrollOffset.y; - scaleDiff.height = 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; } void CompositorParent::SetFirstPaintViewport(const nsIntPoint& aOffset, float aZoom, const nsIntRect& aPageRect, const gfx::Rect& aCssPageRect)
--- a/gfx/layers/ipc/CompositorParent.h +++ b/gfx/layers/ipc/CompositorParent.h @@ -184,16 +184,17 @@ private: void PauseComposition(); void ResumeComposition(); void ResumeCompositionAndResize(int width, int height); void ForceComposition(); // 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. bool ApplyAsyncContentTransformToTree(TimeStamp aCurrentFrame, Layer* aLayer, bool* aWantNextFrame); inline PlatformThreadId CompositorThreadID();