Bug 754233 - Handle negative layer coordinate in Tiled layers. r=ajuma

This commit is contained in:
Benoit Girard 2012-05-17 15:47:53 -04:00
parent e00a607d2a
commit 1f9de263ac
3 changed files with 73 additions and 33 deletions

View File

@ -107,8 +107,14 @@ public:
mLastPaintRegion = aLastPaintRegion;
}
// Given a position i, this function returns the position inside the current tile.
int GetTileStart(int i) const {
return (i >= 0) ? (i % GetTileLength())
: ((GetTileLength() - (-i % GetTileLength())) % GetTileLength());
}
// Rounds the given coordinate down to the nearest tile boundary.
int RoundDownToTileEdge(int aX) const { return aX - aX % GetTileLength(); }
int RoundDownToTileEdge(int aX) const { return aX - GetTileStart(aX); }
protected:
// The implementor should call Update() to change
@ -154,16 +160,34 @@ public:
virtual void PaintedTiledLayerBuffer(const BasicTiledLayerBuffer* aTiledBuffer) = 0;
};
// Normal integer division truncates towards zero,
// we instead want to floor to hangle negative numbers.
static int floor_div(int a, int b)
{
int rem = a % b;
int div = a/b;
if (rem == 0) {
return div;
} else {
// If the signs are different substract 1.
int sub;
sub = a ^ b;
// The results of this shift is either 0 or -1.
sub >>= 8*sizeof(int)-1;
return div+sub;
}
}
template<typename Derived, typename Tile> Tile
TiledLayerBuffer<Derived, Tile>::GetTile(const nsIntPoint& aTileOrigin) const
{
// TODO Cache firstTileOriginX/firstTileOriginY
// Find the tile x/y of the first tile and the target tile relative to the (0, 0)
// origin, the difference is the tile x/y relative to the start of the tile buffer.
int firstTileX = mValidRegion.GetBounds().x / GetTileLength();
int firstTileY = mValidRegion.GetBounds().y / GetTileLength();
return GetTile(aTileOrigin.x / GetTileLength() - firstTileX,
aTileOrigin.y / GetTileLength() - firstTileY);
int firstTileX = floor_div(mValidRegion.GetBounds().x, GetTileLength());
int firstTileY = floor_div(mValidRegion.GetBounds().y, GetTileLength());
return GetTile(floor_div(aTileOrigin.x, GetTileLength()) - firstTileX,
floor_div(aTileOrigin.y, GetTileLength()) - firstTileY);
}
template<typename Derived, typename Tile> Tile
@ -177,10 +201,10 @@ template<typename Derived, typename Tile> bool
TiledLayerBuffer<Derived, Tile>::RemoveTile(const nsIntPoint& aTileOrigin,
Tile& aRemovedTile)
{
int firstTileX = mValidRegion.GetBounds().x / GetTileLength();
int firstTileY = mValidRegion.GetBounds().y / GetTileLength();
return RemoveTile(aTileOrigin.x / GetTileLength() - firstTileX,
aTileOrigin.y / GetTileLength() - firstTileY,
int firstTileX = floor_div(mValidRegion.GetBounds().x, GetTileLength());
int firstTileY = floor_div(mValidRegion.GetBounds().y, GetTileLength());
return RemoveTile(floor_div(aTileOrigin.x, GetTileLength()) - firstTileX,
floor_div(aTileOrigin.y, GetTileLength()) - firstTileY,
aRemovedTile);
}
@ -221,17 +245,17 @@ TiledLayerBuffer<Derived, Tile>::Update(const nsIntRegion& aNewValidRegion,
int tileX = 0;
int tileY;
// Iterate over the new drawing bounds in steps of tiles.
for (int x = newBound.x; x < newBound.XMost(); tileX++) {
for (int32_t x = newBound.x; x < newBound.XMost(); tileX++) {
// Compute tileRect(x,y,width,height) in layer space coordinate
// giving us the rect of the tile that hits the newBounds.
int width = GetTileLength() - x % GetTileLength();
int width = GetTileLength() - GetTileStart(x);
if (x + width > newBound.XMost()) {
width = newBound.x + newBound.width - x;
}
tileY = 0;
for (int y = newBound.y; y < newBound.YMost(); tileY++) {
int height = GetTileLength() - y % GetTileLength();
for (int32_t y = newBound.y; y < newBound.YMost(); tileY++) {
int height = GetTileLength() - GetTileStart(y);
if (y + height > newBound.y + newBound.height) {
height = newBound.y + newBound.height - y;
}
@ -241,8 +265,8 @@ TiledLayerBuffer<Derived, Tile>::Update(const nsIntRegion& aNewValidRegion,
// This old tiles contains some valid area so move it to the new tile
// buffer. Replace the tile in the old buffer with a placeholder
// to leave the old buffer index unaffected.
int tileX = (x - oldBufferOrigin.x) / GetTileLength();
int tileY = (y - oldBufferOrigin.y) / GetTileLength();
int tileX = floor_div(x - oldBufferOrigin.x, GetTileLength());
int tileY = floor_div(y - oldBufferOrigin.y, GetTileLength());
int index = tileX * oldRetainedHeight + tileY;
// The tile may have been removed, skip over it in this case.
@ -294,18 +318,21 @@ TiledLayerBuffer<Derived, Tile>::Update(const nsIntRegion& aNewValidRegion,
// We also know that any place holder tile in the new buffer must be
// allocated.
tileX = 0;
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
printf_stderr("Update %i, %i, %i, %i\n", newBound.x, newBound.y, newBound.width, newBound.height);
#endif
for (int x = newBound.x; x < newBound.x + newBound.width; tileX++) {
// Compute tileRect(x,y,width,height) in layer space coordinate
// giving us the rect of the tile that hits the newBounds.
int tileStartX = RoundDownToTileEdge(x);
int width = GetTileLength() - x % GetTileLength();
int width = GetTileLength() - GetTileStart(x);
if (x + width > newBound.XMost())
width = newBound.XMost() - x;
tileY = 0;
for (int y = newBound.y; y < newBound.y + newBound.height; tileY++) {
int tileStartY = RoundDownToTileEdge(y);
int height = GetTileLength() - y % GetTileLength();
int height = GetTileLength() - GetTileStart(y);
if (y + height > newBound.YMost()) {
height = newBound.YMost() - y;
}
@ -320,8 +347,8 @@ TiledLayerBuffer<Derived, Tile>::Update(const nsIntRegion& aNewValidRegion,
// because we can reuse all of the content from the
// previous buffer.
#ifdef DEBUG
int currTileX = (x - newBufferOrigin.x) / GetTileLength();
int currTileY = (y - newBufferOrigin.y) / GetTileLength();
int currTileX = floor_div(x - newBufferOrigin.x, GetTileLength());
int currTileY = floor_div(y - newBufferOrigin.y, GetTileLength());
int index = currTileX * mRetainedHeight + currTileY;
NS_ABORT_IF_FALSE(!newValidRegion.Intersects(tileRect) ||
!IsPlaceholder(newRetainedTiles.
@ -332,8 +359,8 @@ TiledLayerBuffer<Derived, Tile>::Update(const nsIntRegion& aNewValidRegion,
continue;
}
int tileX = (x - newBufferOrigin.x) / GetTileLength();
int tileY = (y - newBufferOrigin.y) / GetTileLength();
int tileX = floor_div(x - newBufferOrigin.x, GetTileLength());
int tileY = floor_div(y - newBufferOrigin.y, GetTileLength());
int index = tileX * mRetainedHeight + tileY;
NS_ABORT_IF_FALSE(index >= 0 && index < newRetainedTiles.Length(), "index out of range");
Tile newTile = newRetainedTiles[index];
@ -349,6 +376,9 @@ TiledLayerBuffer<Derived, Tile>::Update(const nsIntRegion& aNewValidRegion,
newTile = AsDerived().ValidateTile(newTile, nsIntPoint(tileStartX, tileStartY),
tileDrawRegion);
NS_ABORT_IF_FALSE(!IsPlaceholder(newTile), "index out of range");
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
printf_stderr("Store Validate tile %i, %i -> %i\n", tileStartX, tileStartY, index);
#endif
newRetainedTiles[index] = newTile;
y += height;

View File

@ -125,12 +125,12 @@ ReusableTileStoreOGL::HarvestTiles(TiledThebesLayerOGL* aLayer,
uint16_t tileSize = aVideoMemoryTiledBuffer->GetTileLength();
nsIntRect validBounds = aOldValidRegion.GetBounds();
for (int x = validBounds.x; x < validBounds.XMost();) {
int w = tileSize - x % tileSize;
int w = tileSize - aVideoMemoryTiledBuffer->GetTileStart(x);
if (x + w > validBounds.x + validBounds.width)
w = validBounds.x + validBounds.width - x;
for (int y = validBounds.y; y < validBounds.YMost();) {
int h = tileSize - y % tileSize;
int h = tileSize - aVideoMemoryTiledBuffer->GetTileStart(y);
if (y + h > validBounds.y + validBounds.height)
h = validBounds.y + validBounds.height - y;
@ -273,8 +273,18 @@ ReusableTileStoreOGL::DrawTiles(TiledThebesLayerOGL* aLayer,
// XXX If we have multiple tiles covering the same area, we will
// end up with rendering artifacts if the aLayer isn't opaque.
uint16_t tileStartX = tile->mTileOrigin.x % tile->mTileSize;
uint16_t tileStartY = tile->mTileOrigin.y % tile->mTileSize;
int32_t tileStartX;
int32_t tileStartY;
if (tile->mTileOrigin.x >= 0) {
tileStartX = tile->mTileOrigin.x % tile->mTileSize;
} else {
tileStartX = (tile->mTileSize - (-tile->mTileOrigin.x % tile->mTileSize)) % tile->mTileSize;
}
if (tile->mTileOrigin.y >= 0) {
tileStartY = tile->mTileOrigin.y % tile->mTileSize;
} else {
tileStartY = (tile->mTileSize - (-tile->mTileOrigin.y % tile->mTileSize)) % tile->mTileSize;
}
nsIntPoint tileOffset(tile->mTileOrigin.x - tileStartX, tile->mTileOrigin.y - tileStartY);
nsIntSize textureSize(tile->mTileSize, tile->mTileSize);
aLayer->RenderTile(tile->mTexture, transform, aRenderOffset, tileRegion, tileOffset, textureSize, aMaskLayer);

View File

@ -237,18 +237,18 @@ TiledThebesLayerOGL::RenderLayer(int aPreviousFrameBuffer, const nsIntPoint& aOf
const nsIntRegion& visibleRegion = GetEffectiveVisibleRegion();
const nsIntRect visibleRect = visibleRegion.GetBounds();
unsigned int rowCount = 0;
int tileX = 0;
for (size_t x = visibleRect.x; x < visibleRect.x + visibleRect.width;) {
uint32_t rowCount = 0;
uint32_t tileX = 0;
for (int32_t x = visibleRect.x; x < visibleRect.x + visibleRect.width;) {
rowCount++;
uint16_t tileStartX = x % mVideoMemoryTiledBuffer.GetTileLength();
uint16_t w = mVideoMemoryTiledBuffer.GetTileLength() - tileStartX;
int32_t tileStartX = mVideoMemoryTiledBuffer.GetTileStart(x);
int16_t w = mVideoMemoryTiledBuffer.GetTileLength() - tileStartX;
if (x + w > visibleRect.x + visibleRect.width)
w = visibleRect.x + visibleRect.width - x;
int tileY = 0;
for (size_t y = visibleRect.y; y < visibleRect.y + visibleRect.height;) {
uint16_t tileStartY = y % mVideoMemoryTiledBuffer.GetTileLength();
uint16_t h = mVideoMemoryTiledBuffer.GetTileLength() - tileStartY;
for (int32_t y = visibleRect.y; y < visibleRect.y + visibleRect.height;) {
int32_t tileStartY = mVideoMemoryTiledBuffer.GetTileStart(y);
int16_t h = mVideoMemoryTiledBuffer.GetTileLength() - tileStartY;
if (y + h > visibleRect.y + visibleRect.height)
h = visibleRect.y + visibleRect.height - y;