Bug 722068 - Fix invalidation during animations in MultiTileLayer. r=pcwalton
authorChris Lord <chrislord.net@gmail.com>
Tue, 31 Jan 2012 09:36:02 +0000
changeset 85825 8919c54229e147cbe099f9e3ad59ee9a86ab4580
parent 85824 43db43f13cdeb20d5ef62bdaddca552b5b0d91f8
child 85826 159c690b5aa549f18640e4399ca691b02a292d36
push id21964
push userbmo@edmorley.co.uk
push dateTue, 31 Jan 2012 16:45:57 +0000
treeherdermozilla-central@f64c0d0b436b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspcwalton
bugs722068
milestone12.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
Bug 722068 - Fix invalidation during animations in MultiTileLayer. r=pcwalton The buffer in MultiTileLayer is invalidated each time the origin or resolution changes. MultiTileLayer was using the last updated origin/resolution instead of the last set, so if Gecko was animating and locked the layer for long enough, the buffer would be incorrectly invalidated due to the origin/resolution not being updated.
mobile/android/base/gfx/MultiTileLayer.java
--- a/mobile/android/base/gfx/MultiTileLayer.java
+++ b/mobile/android/base/gfx/MultiTileLayer.java
@@ -66,16 +66,21 @@ public class MultiTileLayer extends Laye
     private final IntSize mTileSize;
     private IntSize mBufferSize;
     private Region mDirtyRegion;
     private Region mValidRegion;
     private Point mRenderOffset;
     private final LinkedList<SubTile> mTiles;
     private final HashMap<Long, SubTile> mPositionHash;
 
+    // Copies of the last set origin/resolution, to decide when to invalidate
+    // the buffer
+    private Point mOrigin;
+    private float mResolution;
+
     public MultiTileLayer(CairoImage image, IntSize tileSize) {
         super();
 
         mImage = image;
         mTileSize = tileSize;
         mBufferSize = new IntSize(0, 0);
         mDirtyRegion = new Region();
         mValidRegion = new Region();
@@ -97,17 +102,17 @@ public class MultiTileLayer extends Laye
         mDirtyRegion.union(dirtyRect);
         mValidRegion.union(dirtyRect);
     }
 
     /**
      * Invalidates the backing buffer. Data will not be uploaded from an invalid
      * backing buffer. This method is only valid inside a transaction.
      */
-    public void invalidateBuffer() {
+    protected void invalidateBuffer() {
         if (!inTransaction()) {
             throw new RuntimeException("invalidateBuffer() is only valid inside a transaction");
         }
 
         mDirtyRegion.setEmpty();
         mValidRegion.setEmpty();
     }
 
@@ -176,27 +181,26 @@ public class MultiTileLayer extends Laye
         tile.beginTransaction(null);
         try {
             if (reused) {
                 // Invalidate any area that isn't represented in the current
                 // buffer. This is done as SingleTileLayer always updates the
                 // entire width, regardless of the dirty-rect's width, and so
                 // can override existing data.
                 Point origin = getOffsetOrigin();
-                Rect validRect = tile.getValidTextureArea();
-                validRect.offset(tileOrigin.x - origin.x, tileOrigin.y - origin.y);
-                Region validRegion = new Region(validRect);
+                Region validRegion = new Region(tile.getValidTextureArea());
+                validRegion.translate(tileOrigin.x - origin.x, tileOrigin.y - origin.y);
                 validRegion.op(mValidRegion, Region.Op.INTERSECT);
 
                 // SingleTileLayer can't draw complex regions, so in that case,
                 // just invalidate the entire area.
                 tile.invalidateTexture();
-                if (!validRegion.isComplex()) {
-                    validRect.set(validRegion.getBounds());
-                    validRect.offset(origin.x - tileOrigin.x, origin.y - tileOrigin.y);
+                if (!validRegion.isEmpty() && !validRegion.isComplex()) {
+                    validRegion.translate(origin.x - tileOrigin.x, origin.y - tileOrigin.y);
+                    tile.getValidTextureArea().set(validRegion.getBounds());
                 }
             } else {
                 // Update tile metrics
                 tile.setOrigin(tileOrigin);
                 tile.setResolution(getResolution());
 
                 // Make sure that non-reused tiles are marked as invalid before
                 // uploading new content.
@@ -281,32 +285,31 @@ public class MultiTileLayer extends Laye
         // off-buffer tiles, but this is a rare case that we allow for
         // optimisation purposes.
         //
         // XXX Ideally, we want to remove this second invalidation clause
         //     somehow. It may be possible to know if off-screen tiles are
         //     valid by monitoring reflows on the browser element, or
         //     something along these lines.
         LinkedList<SubTile> invalidTiles = new LinkedList<SubTile>();
-        Rect bounds = mValidRegion.getBounds();
         for (ListIterator<SubTile> i = mTiles.listIterator(); i.hasNext();) {
             SubTile tile = i.next();
 
             if (tile.key == null) {
                 continue;
             }
 
             RectF tileBounds = tile.getBounds(context, new FloatSize(tile.getSize()));
             Rect tilespaceTileBounds =
                 RectUtils.round(RectUtils.scale(tileBounds, scaleFactor));
             tilespaceTileBounds.offset(-origin.x, -origin.y);
 
             // First bracketed clause: Invalidate off-screen, off-buffer tiles
             // Second: Invalidate visible tiles at the wrong resolution that have updates
-            if ((!Rect.intersects(bounds, tilespaceTileBounds) &&
+            if ((!opRegion.op(tilespaceTileBounds, mValidRegion, Region.Op.INTERSECT) &&
                  !Rect.intersects(tilespaceViewport, tilespaceTileBounds)) ||
                 (!FloatUtils.fuzzyEquals(tile.getResolution(), getResolution()) &&
                  opRegion.op(tilespaceTileBounds, updateRegion, Region.Op.INTERSECT))) {
                 tile.invalidateTexture();
 
                 // Add to the list of invalid tiles and remove from the main list
                 invalidTiles.add(tile);
                 i.remove();
@@ -410,43 +413,41 @@ public class MultiTileLayer extends Laye
             if (RectF.intersects(layerBounds, context.viewport)) {
                 layer.draw(context);
             }
         }
     }
 
     @Override
     public void setOrigin(Point origin) {
-        Point oldOrigin = getOrigin();
-
-        if (!origin.equals(oldOrigin)) {
+        if (mOrigin == null || !origin.equals(mOrigin)) {
+            mOrigin = origin;
             super.setOrigin(origin);
             invalidateBuffer();
         }
     }
 
     @Override
     public void setResolution(float resolution) {
-        float oldResolution = getResolution();
-
-        if (!FloatUtils.fuzzyEquals(resolution, oldResolution)) {
+        if (!FloatUtils.fuzzyEquals(resolution, mResolution)) {
+            mResolution = resolution;
             super.setResolution(resolution);
             invalidateBuffer();
         }
     }
 
     public void setRenderOffset(Point offset) {
         mRenderOffset.set(offset.x, offset.y);
     }
 
     /**
      * Invalidates all sub-tiles. This should be called if the source backing
      * this layer has changed. This method is only valid inside a transaction.
      */
-    public void invalidateTiles() {
+    protected void invalidateTiles() {
         if (!inTransaction()) {
             throw new RuntimeException("invalidateTiles() is only valid inside a transaction");
         }
 
         for (SubTile tile : mTiles) {
             // Remove tile from position hash and mark it as invalid
             if (tile.key != null) {
                 mPositionHash.remove(tile.key);