diff options
author | Tomaž Vajngerl <tomaz.vajngerl@collabora.com> | 2014-10-01 13:51:00 +0200 |
---|---|---|
committer | Tomaž Vajngerl <tomaz.vajngerl@collabora.com> | 2014-10-04 17:49:38 +0200 |
commit | 7afb0e2491ac47021412529e3330f3924991d234 (patch) | |
tree | cc65d19cb1434b9b98e988a24c2af3cf25dec7b4 | |
parent | ce77933dbe278f59afb7e6a74c3b160b1d33b6df (diff) |
android: replace MultiTileLayer with new & simpler DynamicTileLayer
Change-Id: Idec2246975a65f8ce664642a4ef49415e20ca187
3 files changed, 199 insertions, 275 deletions
diff --git a/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/DynamicTileLayer.java b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/DynamicTileLayer.java new file mode 100644 index 000000000000..03da4bfe4ad7 --- /dev/null +++ b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/DynamicTileLayer.java @@ -0,0 +1,197 @@ +package org.mozilla.gecko.gfx; + +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.Region; +import android.util.Log; + +import org.libreoffice.TileProvider; +import org.mozilla.gecko.util.FloatUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +public class DynamicTileLayer extends Layer { + private static final String LOGTAG = DynamicTileLayer.class.getSimpleName(); + + private final List<SubTile> tiles = new CopyOnWriteArrayList<SubTile>(); + private TileProvider tileProvider; + private final FloatSize tileSize; + private RectF currentViewport = new RectF(); + + public DynamicTileLayer() { + this.tileSize = new FloatSize(256, 256); + } + + public DynamicTileLayer(FloatSize tileSize) { + this.tileSize = tileSize; + } + + public void setTileProvider(TileProvider tileProvider) { + this.tileProvider = tileProvider; + } + + public void invalidate() { + for (SubTile layer : tiles) { + layer.invalidate(); + } + } + + @Override + public void beginTransaction() { + super.beginTransaction(); + for (SubTile tile : tiles) { + tile.beginTransaction(); + } + } + + @Override + public void endTransaction() { + for (SubTile tile : tiles) { + tile.endTransaction(); + } + super.endTransaction(); + } + + @Override + public void draw(RenderContext context) { + for (SubTile tile : tiles) { + if (RectF.intersects(tile.getBounds(context), context.viewport)) { + tile.draw(context); + } + } + } + + @Override + protected void performUpdates(RenderContext context) { + super.performUpdates(context); + + refreshTileMetrics(); + + for (SubTile tile : tiles) { + tile.performUpdates(context); + } + } + + @Override + public Region getValidRegion(RenderContext context) { + Region validRegion = new Region(); + for (SubTile tile : tiles) { + validRegion.op(tile.getValidRegion(context), Region.Op.UNION); + } + + return validRegion; + } + + @Override + public void setResolution(float newResolution) { + super.setResolution(newResolution); + for (SubTile tile : tiles) { + tile.setResolution(newResolution); + } + } + + private void refreshTileMetrics() { + for (SubTile tile : tiles) { + tile.beginTransaction(); + + Rect position = tile.getPosition(); + float positionX = tile.x / tile.zoom; + float positionY = tile.y / tile.zoom; + float tileSizeWidth = tileSize.width / tile.zoom; + float tileSizeHeight = tileSize.height / tile.zoom; + position.set((int) positionX, (int) positionY, (int) (positionX + tileSizeWidth + 1), (int) (positionY + tileSizeHeight + 1)); + tile.setPosition(position); + + tile.endTransaction(); + } + } + + private RectF roundToTileSize(RectF input, FloatSize tileSize) { + float minX = ((int)(input.left / tileSize.width)) * tileSize.width; + float minY = ((int)(input.top / tileSize.height)) * tileSize.height; + float maxX = ((int)(input.right / tileSize.width) + 1) * tileSize.width; + float maxY = ((int)(input.bottom / tileSize.height) + 1) * tileSize.height; + return new RectF(minX, minY, maxX, maxY); + } + + private RectF inflate(RectF rect, FloatSize inflateSize) { + RectF newRect = new RectF(rect); + newRect.left -= inflateSize.width; + newRect.left = newRect.left < 0.0f ? 0.0f : newRect.left; + + newRect.top -= inflateSize.height; + newRect.top = newRect.top < 0.0f ? 0.0f : newRect.top; + + newRect.right += inflateSize.width; + newRect.bottom += inflateSize.height; + + return newRect; + } + + public void reevaluateTiles(ImmutableViewportMetrics viewportMetrics) { + RectF newCurrentViewPort = inflate(roundToTileSize(viewportMetrics.getViewport(), tileSize), tileSize); + + if (!currentViewport.equals(newCurrentViewPort)) { + Log.i(LOGTAG, "reevaluateTiles " + currentViewport + " " + newCurrentViewPort); + currentViewport = newCurrentViewPort; + clearMarkedTiles(); + addNewTiles(viewportMetrics); + markTiles(viewportMetrics); + } + } + + private void addNewTiles(ImmutableViewportMetrics viewportMetrics) { + for (float y = currentViewport.top; y < currentViewport.bottom; y += tileSize.height) { + if (y > viewportMetrics.getPageHeight()) { + continue; + } + for (float x = currentViewport.left; x < currentViewport.right; x += tileSize.width) { + if (x > viewportMetrics.getPageWidth()) { + continue; + } + boolean contains = false; + for (SubTile tile : tiles) { + if (tile.x == x && tile.y == y && tile.zoom == viewportMetrics.zoomFactor) { + contains = true; + } + } + if (!contains) { + CairoImage image = tileProvider.createTile(x, y, tileSize, viewportMetrics.zoomFactor); + SubTile tile = new SubTile(image, (int) x, (int) y, viewportMetrics.zoomFactor); + tile.beginTransaction(); + tiles.add(tile); + } + } + } + } + + private void clearMarkedTiles() { + List<SubTile> tilesToRemove = new ArrayList<SubTile>(); + for (SubTile tile : tiles) { + if (tile.markedForRemoval) { + tile.destroy(); + tilesToRemove.add(tile); + } + } + tiles.removeAll(tilesToRemove); + } + + private void markTiles(ImmutableViewportMetrics viewportMetrics) { + for (SubTile tile : tiles) { + if (FloatUtils.fuzzyEquals(tile.zoom, viewportMetrics.zoomFactor)) { + RectF tileRect = new RectF(tile.x, tile.y, tile.x + tileSize.width, tile.y + tileSize.height); + if (!RectF.intersects(currentViewport, tileRect)) { + tile.markForRemoval(); + } + } else { + tile.markForRemoval(); + } + } + } + + public void clearAllTiles() { + tiles.clear(); + } +} diff --git a/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/GeckoLayerClient.java b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/GeckoLayerClient.java index 9c3a893d48df..9ae462b68b40 100644 --- a/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/GeckoLayerClient.java +++ b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/GeckoLayerClient.java @@ -62,7 +62,7 @@ public class GeckoLayerClient implements LayerView.Listener { private boolean mRecordDrawTimes; private DrawTimingQueue mDrawTimingQueue; - private MultiTileLayer mRootLayer; + private DynamicTileLayer mRootLayer; /* The viewport that Gecko is currently displaying. */ private ImmutableViewportMetrics mGeckoViewport; @@ -88,7 +88,7 @@ public class GeckoLayerClient implements LayerView.Listener { mLayerController = layerController; - mRootLayer = new MultiTileLayer(); + mRootLayer = new DynamicTileLayer(); view.setListener(this); layerController.setRoot(mRootLayer); diff --git a/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/MultiTileLayer.java b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/MultiTileLayer.java deleted file mode 100644 index 7d1306e76416..000000000000 --- a/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/MultiTileLayer.java +++ /dev/null @@ -1,273 +0,0 @@ -/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- -* ***** BEGIN LICENSE BLOCK ***** -* Version: MPL 1.1/GPL 2.0/LGPL 2.1 -* -* The contents of this file are subject to the Mozilla Public License Version -* 1.1 (the "License"); you may not use this file except in compliance with -* the License. You may obtain a copy of the License at -* http://www.mozilla.org/MPL/ -* -* Software distributed under the License is distributed on an "AS IS" basis, -* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License -* for the specific language governing rights and limitations under the -* License. -* -* The Original Code is Mozilla Android code. -* -* The Initial Developer of the Original Code is Mozilla Foundation. -* Portions created by the Initial Developer are Copyright (C) 2011-2012 -* the Initial Developer. All Rights Reserved. -* -* Contributor(s): -* Chris Lord <chrislord.net@gmail.com> -* Arkady Blyakher <rkadyb@mit.edu> -* -* Alternatively, the contents of this file may be used under the terms of -* either the GNU General Public License Version 2 or later (the "GPL"), or -* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -* in which case the provisions of the GPL or the LGPL are applicable instead -* of those above. If you wish to allow use of your version of this file only -* under the terms of either the GPL or the LGPL, and not to allow others to -* use your version of this file under the terms of the MPL, indicate your -* decision by deleting the provisions above and replace them with the notice -* and other provisions required by the GPL or the LGPL. If you do not delete -* the provisions above, a recipient may use your version of this file under -* the terms of any one of the MPL, the GPL or the LGPL. -* -* ***** END LICENSE BLOCK ***** */ - -package org.mozilla.gecko.gfx; - -import android.graphics.Point; -import android.graphics.Rect; -import android.graphics.RectF; -import android.graphics.Region; - -import org.libreoffice.TileProvider; -import org.mozilla.gecko.util.FloatUtils; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; - -public class MultiTileLayer extends Layer { - private static final String LOGTAG = "MultiTileLayer"; - - private static int TILE_SIZE = 256; - private final List<SubTile> mTiles = new CopyOnWriteArrayList<SubTile>(); - private TileProvider tileProvider; - private RectF currentViewPort = new RectF(); - - public void invalidate() { - for (SubTile layer : mTiles) { - layer.invalidate(); - } - } - - private void validateTiles() { - // Set tile origins and resolution - Point origin = new Point(); - refreshTileMetrics(origin, getResolution(), false); - } - - @Override - protected void performUpdates(RenderContext context) { - super.performUpdates(context); - - validateTiles(); - - // Iterate over the tiles and decide which ones we'll be drawing - int dirtyTiles = 0; - boolean screenUpdateDone = false; - SubTile firstDirtyTile = null; - for (SubTile layer : mTiles) { - // First do a non-texture update to make sure coordinates are - // up-to-date. - layer.performUpdates(context); - - RectF layerBounds = layer.getBounds(context); - - if (!RectF.intersects(layerBounds, context.viewport)) { - if (firstDirtyTile == null) { - firstDirtyTile = layer; - } - dirtyTiles++; - } else { - // This tile intersects with the screen and is dirty, - // update it immediately. - screenUpdateDone = true; - layer.performUpdates(context); - } - } - - // Now if no tiles that intersect with the screen were updated, update - // a single tile that doesn't (if there are any). This has the effect - // of spreading out non-critical texture upload over time, and smoothing - // upload-related hitches. - if (!screenUpdateDone && firstDirtyTile != null) { - firstDirtyTile.performUpdates(context); - dirtyTiles--; - } - - } - - private void refreshTileMetrics(Point origin, float resolution, boolean inTransaction) { - for (SubTile layer : mTiles) { - if (!inTransaction) { - layer.beginTransaction(); - } - - if (origin != null) { - Rect position = layer.getPosition(); - float positionX = origin.x + (layer.x / layer.zoom); - float positionY = origin.y + (layer.y / layer.zoom); - float tileSize = TILE_SIZE / layer.zoom; - position.set((int) positionX, (int) positionY, (int) (positionX + tileSize + 1), (int) (positionY + tileSize + 1)); - layer.setPosition(position); - } - if (resolution >= 0.0f) { - layer.setResolution(resolution); - } - - if (!inTransaction) { - layer.endTransaction(); - } - } - } - - @Override - public void setResolution(float newResolution) { - super.setResolution(newResolution); - refreshTileMetrics(null, newResolution, true); - } - - @Override - public void beginTransaction() { - super.beginTransaction(); - - for (SubTile layer : mTiles) { - layer.beginTransaction(); - } - } - - @Override - public void endTransaction() { - for (SubTile layer : mTiles) { - layer.endTransaction(); - } - super.endTransaction(); - } - - private RectF roundToTileSize(RectF input, int tileSize) { - float minX = (Math.round(input.left) / tileSize) * tileSize; - float minY = (Math.round(input.top) / tileSize) * tileSize; - float maxX = ((Math.round(input.right) / tileSize) + 1) * tileSize; - float maxY = ((Math.round(input.bottom) / tileSize) + 1) * tileSize; - return new RectF(minX, minY, maxX, maxY); - } - - private RectF inflate(RectF rect, float inflateSize) { - RectF newRect = new RectF(rect); - newRect.left -= inflateSize; - newRect.left = newRect.left < 0.0f ? 0.0f : newRect.left; - - newRect.top -= inflateSize; - newRect.top = newRect.top < 0.0f ? 0.0f : newRect.top; - - newRect.right += inflateSize; - newRect.bottom += inflateSize; - - return newRect; - } - - @Override - public void draw(RenderContext context) { - for (SubTile layer : mTiles) { - // Avoid work, only draw tiles that intersect with the viewport - RectF layerBounds = layer.getBounds(context); - - if (RectF.intersects(layerBounds, context.viewport)) { - layer.draw(context); - } - } - } - - @Override - public Region getValidRegion(RenderContext context) { - Region validRegion = new Region(); - for (SubTile tile : mTiles) { - validRegion.op(tile.getValidRegion(context), Region.Op.UNION); - } - - return validRegion; - } - - public void setTileProvider(TileProvider tileProvider) { - this.tileProvider = tileProvider; - } - - public void reevaluateTiles(ImmutableViewportMetrics viewportMetrics) { - RectF newCurrentViewPort = inflate(roundToTileSize(viewportMetrics.getViewport(), TILE_SIZE), TILE_SIZE); - - if (currentViewPort != newCurrentViewPort) { - currentViewPort = newCurrentViewPort; - clearMarkedTiles(); - addNewTiles(viewportMetrics); - markTiles(viewportMetrics); - } - } - - private void clearMarkedTiles() { - List<SubTile> tilesToRemove = new ArrayList<SubTile>(); - for(SubTile tile : mTiles) { - if (tile.markedForRemoval) { - tile.destroy(); - tilesToRemove.add(tile); - } - } - mTiles.removeAll(tilesToRemove); - } - - private void addNewTiles(ImmutableViewportMetrics viewportMetrics) { - for (float y = currentViewPort.top; y < currentViewPort.bottom; y += TILE_SIZE) { - if (y > viewportMetrics.getPageHeight()) { - continue; - } - for (float x = currentViewPort.left; x < currentViewPort.right; x += TILE_SIZE) { - if (x > viewportMetrics.getPageWidth()) { - continue; - } - boolean contains = false; - for (SubTile tile : mTiles) { - if (tile.x == x && tile.y == y && tile.zoom == viewportMetrics.zoomFactor) { - contains = true; - } - } - if (!contains) { - CairoImage image = tileProvider.createTile(x, y, new FloatSize(TILE_SIZE, TILE_SIZE), viewportMetrics.zoomFactor); - SubTile tile = new SubTile(image, (int)x, (int)y, viewportMetrics.zoomFactor); - tile.beginTransaction(); - mTiles.add(tile); - } - } - } - } - - private void markTiles(ImmutableViewportMetrics viewportMetrics) { - for (SubTile tile : mTiles) { - if (FloatUtils.fuzzyEquals(tile.zoom, viewportMetrics.zoomFactor)) { - RectF tileRect = new RectF(tile.x, tile.y, tile.x + TILE_SIZE, tile.y + TILE_SIZE); - if (!RectF.intersects(currentViewPort, tileRect)) { - tile.markForRemoval(); - } - } else { - tile.markForRemoval(); - } - } - } - - public void clearAllTiles() { - mTiles.clear(); - } -} - |