From 773061c1f7d120b74a19d1cb30f4001593321a39 Mon Sep 17 00:00:00 2001 From: Chris Lord Date: Thu, 26 Jan 2012 20:19:35 +0000 Subject: [PATCH] Bug 721070 - Checkerboarding at bottom after pinch zooming out. r=kats,pcwalton Certain conditions would cause MultiTileLayer to incorrectly invalidate tiles, or to reuse tiles incorrectly, which would cause checkerboarding (sometimes permanent until a redraw occurs). This addresses said issues: - Removes manual invalidation on Document:Shown and Tab:Selected. This is unnecessary, as the entire buffer will be invalidated when this happens anyway. Sometimes Document:Shown happens *after* drawing has occurred, which caused the entire screen to checkerboard incorrectly. - Fix re-using off-screen tiles with the incorrect resolution. Tiles are stored in a hash-map based on their unscaled position. As only tiles that intersect with the update region in tile-space are invalidated, sometimes tiles that were off-screen, but whose unscaled tile origin appears on-screen would be incorrectly re-used. Fix this by checking that a tile's resolution matches the current resolution before reusing it. --- .../base/gfx/GeckoSoftwareLayerClient.java | 13 ------- mobile/android/base/gfx/MultiTileLayer.java | 34 +++++++++++++++++-- 2 files changed, 32 insertions(+), 15 deletions(-) diff --git a/mobile/android/base/gfx/GeckoSoftwareLayerClient.java b/mobile/android/base/gfx/GeckoSoftwareLayerClient.java index 81a80a4bbc49..45208a7a1e57 100644 --- a/mobile/android/base/gfx/GeckoSoftwareLayerClient.java +++ b/mobile/android/base/gfx/GeckoSoftwareLayerClient.java @@ -162,8 +162,6 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL GeckoAppShell.registerGeckoEventListener("Viewport:UpdateAndDraw", this); GeckoAppShell.registerGeckoEventListener("Viewport:UpdateLater", this); - GeckoAppShell.registerGeckoEventListener("Document:Shown", this); - GeckoAppShell.registerGeckoEventListener("Tab:Selected:Done", this); sendResizeEventIfNecessary(); } @@ -252,7 +250,6 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL Point tileOrigin = new Point((origin.x / TILE_SIZE.width) * TILE_SIZE.width, (origin.y / TILE_SIZE.height) * TILE_SIZE.height); mRenderOffset.set(origin.x - tileOrigin.x, origin.y - tileOrigin.y); - ((MultiTileLayer)mTileLayer).invalidateBuffer(); } // If the window size has changed, reallocate the buffer to match. @@ -519,16 +516,6 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL GeckoAppShell.sendEventToGecko(new GeckoEvent(GeckoEvent.DRAW, rect)); } else if ("Viewport:UpdateLater".equals(event)) { mUpdateViewportOnEndDraw = true; - } else if (("Document:Shown".equals(event) || - "Tab:Selected:Done".equals(event)) && - (mTileLayer instanceof MultiTileLayer)) { - beginTransaction(mTileLayer); - try { - ((MultiTileLayer)mTileLayer).invalidateTiles(); - ((MultiTileLayer)mTileLayer).invalidateBuffer(); - } finally { - endTransaction(mTileLayer); - } } } diff --git a/mobile/android/base/gfx/MultiTileLayer.java b/mobile/android/base/gfx/MultiTileLayer.java index 17260e1b66e8..10fb5f112a71 100644 --- a/mobile/android/base/gfx/MultiTileLayer.java +++ b/mobile/android/base/gfx/MultiTileLayer.java @@ -333,7 +333,7 @@ public class MultiTileLayer extends Layer { } // Dirty tile, find out if we already have this tile to reuse. - boolean reusedTile = true; + boolean reusedTile; Point tileOrigin = new Point(x, y); SubTile tile = mPositionHash.get(longFromPoint(tileOrigin)); @@ -343,6 +343,10 @@ public class MultiTileLayer extends Layer { reusedTile = false; } else { mTiles.remove(tile); + + // Reuse the tile (i.e. keep the texture data and metrics) + // only if the resolution matches + reusedTile = FloatUtils.fuzzyEquals(tile.getResolution(), getResolution()); } // Place tile at the end of the tile-list so it isn't re-used. @@ -396,10 +400,36 @@ public class MultiTileLayer extends Layer { @Override public void draw(RenderContext context) { for (SubTile layer : mTiles) { + // Skip invalid tiles + if (layer.key == null) { + continue; + } + // Avoid work, only draw tiles that intersect with the viewport RectF layerBounds = layer.getBounds(context, new FloatSize(layer.getSize())); - if (RectF.intersects(layerBounds, context.viewport)) + if (RectF.intersects(layerBounds, context.viewport)) { layer.draw(context); + } + } + } + + @Override + public void setOrigin(Point origin) { + Point oldOrigin = getOrigin(); + + if (!origin.equals(oldOrigin)) { + super.setOrigin(origin); + invalidateBuffer(); + } + } + + @Override + public void setResolution(float resolution) { + float oldResolution = getResolution(); + + if (!FloatUtils.fuzzyEquals(resolution, oldResolution)) { + super.setResolution(resolution); + invalidateBuffer(); } }