Bug 794200 - Progressive draw tiles in the direction of scrolling. r=bgirard
When scrolling downwards, make sure to fill in tiles from the top, upwards
from the bottom, left from the right and right from the left.
--- a/gfx/layers/Layers.cpp
+++ b/gfx/layers/Layers.cpp
@@ -181,16 +181,47 @@ AppendToString(nsACString& s, const Fram
} // namespace <anon>
namespace mozilla {
namespace layers {
//--------------------------------------------------
// LayerManager
+Layer*
+LayerManager::GetPrimaryScrollableLayer()
+{
+ if (!mRoot) {
+ return nullptr;
+ }
+
+ nsTArray<Layer*> queue;
+ queue.AppendElement(mRoot);
+ while (queue.Length()) {
+ ContainerLayer* containerLayer = queue[0]->AsContainerLayer();
+ queue.RemoveElementAt(0);
+ if (!containerLayer) {
+ continue;
+ }
+
+ const FrameMetrics& frameMetrics = containerLayer->GetFrameMetrics();
+ if (frameMetrics.IsScrollable()) {
+ return containerLayer;
+ }
+
+ Layer* child = containerLayer->GetFirstChild();
+ while (child) {
+ queue.AppendElement(child);
+ child = child->GetNextSibling();
+ }
+ }
+
+ return mRoot;
+}
+
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
@@ -289,16 +289,23 @@ public:
*/
virtual void SetRoot(Layer* aLayer) = 0;
/**
* Can be called anytime
*/
Layer* GetRoot() { return mRoot; }
/**
+ * Does a breadth-first search from the root layer to find the first
+ * scrollable layer.
+ * Can be called any time.
+ */
+ Layer* GetPrimaryScrollableLayer();
+
+ /**
* 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/basic/BasicTiledThebesLayer.cpp
+++ b/gfx/layers/basic/BasicTiledThebesLayer.cpp
@@ -252,39 +252,79 @@ BasicTiledThebesLayer::PaintThebes(gfxCo
mTiledBuffer.GetResolution() == resolution) {
// Paint tiles that have no content before tiles that only have stale content.
nsIntRegion staleRegion = mTiledBuffer.GetValidRegion();
staleRegion.And(staleRegion, regionToPaint);
if (!staleRegion.IsEmpty() && !staleRegion.Contains(regionToPaint)) {
regionToPaint.Sub(regionToPaint, staleRegion);
}
- nsIntRegionRectIterator it(regionToPaint);
- const nsIntRect* rect = it.Next();
- if (!rect)
- return;
+ // The following code decides what order to draw tiles in, based on the
+ // current scroll direction of the primary scrollable layer.
+ // XXX While this code is of a reasonable size currently, it is likely
+ // we'll want to add more comprehensive methods of deciding what
+ // tiles to draw. This is a good candidate for splitting out into a
+ // separate function.
+
+ gfx::Point scrollOffset(0, 0);
+ Layer* primaryScrollable = BasicManager()->GetPrimaryScrollableLayer();
+ if (primaryScrollable) {
+ const FrameMetrics& metrics = primaryScrollable->AsContainerLayer()->GetFrameMetrics();
+ scrollOffset = metrics.mViewportScrollOffset;
+ }
- // Currently we start painting from the first rect of the paint
- // region and convert that into a tile. We should order tiles using
- // their position from relevant user interaction events.
- int paintTileStartX = mTiledBuffer.RoundDownToTileEdge(rect->x);
- int paintTileStartY = mTiledBuffer.RoundDownToTileEdge(rect->y);
+ // First, decide whether to iterate on the region from the beginning or end
+ // of the rect list. This relies on the specific behaviour of nsRegion when
+ // subtracting rects. If we're moving more in the X direction, we draw
+ // tiles by column, otherwise by row.
+ nsIntRegionRectIterator it(regionToPaint);
+ const nsIntRect* rect;
+ int32_t scrollDiffX = scrollOffset.x - mLastScrollOffset.x;
+ int32_t scrollDiffY = scrollOffset.y - mLastScrollOffset.y;
+ if ((NS_ABS(scrollDiffY) > NS_ABS(scrollDiffX) && scrollDiffY >= 0)) {
+ rect = it.Next();
+ } else {
+ const nsIntRect* lastRect;
+ while (lastRect = it.Next()) {
+ rect = lastRect;
+ }
+ }
+
+ // Second, decide what direction to start drawing rects from by checking
+ // the scroll offset difference of the primary scrollable layer. If we're
+ // scrolling to the right, make sure to start from the left, downwards
+ // start from the top, etc.
+ int paintTileStartX, paintTileStartY;
+ if (scrollOffset.x >= mLastScrollOffset.x) {
+ paintTileStartX = mTiledBuffer.RoundDownToTileEdge(rect->x);
+ } else {
+ paintTileStartX = mTiledBuffer.RoundDownToTileEdge(rect->XMost() - 1);
+ }
+
+ if (scrollOffset.y >= mLastScrollOffset.y) {
+ paintTileStartY = mTiledBuffer.RoundDownToTileEdge(rect->y);
+ } else {
+ paintTileStartY = mTiledBuffer.RoundDownToTileEdge(rect->YMost() - 1);
+ }
nsIntRegion maxPaint(
nsIntRect(paintTileStartX, paintTileStartY,
mTiledBuffer.GetTileLength(), mTiledBuffer.GetTileLength()));
if (!maxPaint.Contains(regionToPaint)) {
// The region needed to paint is larger then our progressive chunk size
// therefore update what we want to paint and ask for a new paint transaction.
regionToPaint.And(regionToPaint, maxPaint);
BasicManager()->SetRepeatTransaction();
// Make sure that tiles that fall outside of the visible region are discarded.
mValidRegion.And(mValidRegion, mVisibleRegion);
+ } else {
+ // The transaction is completed, store the last scroll offset.
+ mLastScrollOffset = scrollOffset;
}
// Keep track of what we're about to refresh.
mValidRegion.Or(mValidRegion, regionToPaint);
} else {
mTiledBuffer.SetResolution(resolution);
mValidRegion = mVisibleRegion;
}
--- a/gfx/layers/basic/BasicTiledThebesLayer.h
+++ b/gfx/layers/basic/BasicTiledThebesLayer.h
@@ -156,16 +156,17 @@ class BasicTiledThebesLayer : public The
public BasicImplData,
public BasicShadowableLayer
{
typedef ThebesLayer Base;
public:
BasicTiledThebesLayer(BasicShadowLayerManager* const aManager)
: ThebesLayer(aManager, static_cast<BasicImplData*>(this))
+ , mLastScrollOffset(0, 0)
{
MOZ_COUNT_CTOR(BasicTiledThebesLayer);
}
~BasicTiledThebesLayer()
{
MOZ_COUNT_DTOR(BasicTiledThebesLayer);
}
@@ -206,14 +207,15 @@ private:
const nsIntRegion& aRegionToInvalidate,
bool aDidSelfCopy,
LayerManager::DrawThebesLayerCallback aCallback,
void* aCallbackData)
{ NS_RUNTIMEABORT("Not reached."); }
// Members
BasicTiledLayerBuffer mTiledBuffer;
+ gfx::Point mLastScrollOffset;
};
} // layers
} // mozilla
#endif
--- a/gfx/layers/ipc/CompositorParent.cpp
+++ b/gfx/layers/ipc/CompositorParent.cpp
@@ -525,45 +525,16 @@ CompositorParent::Composite()
printf_stderr("Compositor: Composite took %i ms.\n",
15 + (int)(TimeStamp::Now() - mExpectedComposeTime).ToMilliseconds());
}
#endif
}
// Do a breadth-first search to find the first layer in the tree that is
// scrollable.
-Layer*
-CompositorParent::GetPrimaryScrollableLayer()
-{
- Layer* root = mLayerManager->GetRoot();
-
- nsTArray<Layer*> queue;
- queue.AppendElement(root);
- while (queue.Length()) {
- ContainerLayer* containerLayer = queue[0]->AsContainerLayer();
- queue.RemoveElementAt(0);
- if (!containerLayer) {
- continue;
- }
-
- const FrameMetrics& frameMetrics = containerLayer->GetFrameMetrics();
- if (frameMetrics.IsScrollable()) {
- return containerLayer;
- }
-
- Layer* child = containerLayer->GetFirstChild();
- while (child) {
- queue.AppendElement(child);
- child = child->GetNextSibling();
- }
- }
-
- return root;
-}
-
static void
Translate2D(gfx3DMatrix& aTransform, const gfxPoint& aOffset)
{
aTransform._41 += aOffset.x;
aTransform._42 += aOffset.y;
}
void
@@ -766,17 +737,17 @@ CompositorParent::ApplyAsyncContentTrans
return appliedTransform;
}
bool
CompositorParent::TransformShadowTree(TimeStamp aCurrentFrame)
{
bool wantNextFrame = false;
- Layer* layer = GetPrimaryScrollableLayer();
+ 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(layer, mLastCompose);
--- a/gfx/layers/ipc/CompositorParent.h
+++ b/gfx/layers/ipc/CompositorParent.h
@@ -216,22 +216,16 @@ private:
/**
* Remove a compositor from the global compositor map.
*/
static CompositorParent* RemoveCompositor(uint64_t id);
// Platform specific functions
/**
- * Does a breadth-first search to find the first layer in the tree with a
- * displayport set.
- */
- Layer* GetPrimaryScrollableLayer();
-
- /**
* Recursively applies the given translation to all top-level fixed position
* layers that are descendants of the given layer.
* aScaleDiff is considered to be the scale transformation applied when
* displaying the layers, and is used to make sure the anchor points of
* fixed position layers remain in the same position.
*/
void TransformFixedLayers(Layer* aLayer,
const gfxPoint& aTranslation,