Kaydet (Commit) 42070ee2 authored tarafından Tomaž Vajngerl's avatar Tomaž Vajngerl

android: split DynamicTileLayer, reevaluate tiles directly

Split DynamicTileLayer and move most of the implementation into
ComposedTileLayer except viewport zoom value.

Reevaluate tiles directly in UI thread instead a special call to
LO thread.

Change-Id: I9a4ce499cf35315cd386956484c2df6d5a5f20cc
üst a0b54683
......@@ -2,6 +2,7 @@ package org.libreoffice;
import android.graphics.Rect;
import org.mozilla.gecko.gfx.ComposedTileLayer;
import org.mozilla.gecko.gfx.ImmutableViewportMetrics;
import org.mozilla.gecko.gfx.IntSize;
......@@ -17,12 +18,14 @@ public class LOEvent {
public static final int REDRAW = 8;
public static final int TILE_REQUEST = 9;
public int mType;
public final int mType;
public ImmutableViewportMetrics mViewportMetrics;
public String mTypeString;
public int mPartIndex;
public String mFilename;
public TileIdentifier mTileId;
public ComposedTileLayer mComposedTileLayer;
public LOEvent(int type) {
mType = type;
......@@ -33,9 +36,10 @@ public class LOEvent {
mTypeString = "Size Changed: " + widthPixels + " " + heightPixels;
}
public LOEvent(int type, TileIdentifier tileId) {
public LOEvent(int type, ComposedTileLayer composedTileLayer, TileIdentifier tileId) {
mType = type;
mTypeString = "Tile Request";
mComposedTileLayer = composedTileLayer;
mTileId = tileId;
}
......
......@@ -2,6 +2,7 @@ package org.libreoffice;
import android.graphics.Rect;
import org.mozilla.gecko.gfx.ComposedTileLayer;
import org.mozilla.gecko.gfx.ImmutableViewportMetrics;
import org.mozilla.gecko.gfx.IntSize;
......@@ -39,7 +40,7 @@ public class LOEventFactory {
return new LOEvent(LOEvent.REDRAW);
}
public static LOEvent tileRequest(TileIdentifier tileRequest) {
return new LOEvent(LOEvent.TILE_REQUEST, tileRequest);
public static LOEvent tileRequest(ComposedTileLayer composedTileLayer, TileIdentifier tileRequest) {
return new LOEvent(LOEvent.TILE_REQUEST, composedTileLayer, tileRequest);
}
}
......@@ -5,8 +5,11 @@ import android.graphics.RectF;
import android.util.DisplayMetrics;
import android.util.Log;
import org.mozilla.gecko.gfx.CairoImage;
import org.mozilla.gecko.gfx.ComposedTileLayer;
import org.mozilla.gecko.gfx.GeckoLayerClient;
import org.mozilla.gecko.gfx.ImmutableViewportMetrics;
import org.mozilla.gecko.gfx.SubTile;
import java.util.concurrent.LinkedBlockingQueue;
......@@ -23,22 +26,11 @@ public class LOKitThread extends Thread {
TileProviderFactory.initialize();
}
private void draw() {
if (mTileProvider == null || mApplication == null) {
// called too early...
return;
}
RectF rect = new RectF(0, 0, mTileProvider.getPageWidth(), mTileProvider.getPageHeight());
DisplayMetrics displayMetrics = LibreOfficeMainActivity.mAppContext.getResources().getDisplayMetrics();
mViewportMetrics = new ImmutableViewportMetrics(displayMetrics);
mViewportMetrics = mViewportMetrics.setPageRect(rect, rect);
mLayerClient.reevaluateTiles();
}
private void tileRequest(TileIdentifier tileId) {
private void tileRequest(ComposedTileLayer composedTileLayer, TileIdentifier tileId) {
mLayerClient.beginDrawing();
mLayerClient.addTile(tileId);
CairoImage image = mTileProvider.createTile(tileId.x, tileId.y, tileId.size, tileId.zoom);
SubTile tile = new SubTile(image, tileId);
composedTileLayer.addTile(tile);
mLayerClient.endDrawing(mViewportMetrics);
}
......@@ -49,14 +41,17 @@ public class LOKitThread extends Thread {
return;
}
draw();
RectF rect = new RectF(0, 0, mTileProvider.getPageWidth(), mTileProvider.getPageHeight());
DisplayMetrics displayMetrics = LibreOfficeMainActivity.mAppContext.getResources().getDisplayMetrics();
mViewportMetrics = new ImmutableViewportMetrics(displayMetrics);
mViewportMetrics = mViewportMetrics.setPageRect(rect, rect);
mLayerClient.setPageRect(0, 0, mTileProvider.getPageWidth(), mTileProvider.getPageHeight());
mLayerClient.setViewportMetrics(mLayerClient.getViewportMetrics());
mLayerClient.forceRedraw();
}
/** Invalidate everything + handle the geometry change + draw. */
/** Invalidate everything + handle the geometry change */
private void refresh() {
Bitmap bitmap = mTileProvider.thumbnail(1000);
if (bitmap != null) {
......@@ -84,8 +79,6 @@ public class LOKitThread extends Thread {
mTileProvider = TileProviderFactory.create(mLayerClient, filename);
boolean isReady = mTileProvider.isReady();
if (isReady) {
mLayerClient.setTileProvider(mTileProvider);
LOKitShell.showProgressSpinner();
refresh();
LOKitShell.hideProgressSpinner();
......@@ -132,7 +125,7 @@ public class LOKitThread extends Thread {
changePart(event.mPartIndex);
break;
case LOEvent.TILE_REQUEST:
tileRequest(event.mTileId);
tileRequest(event.mComposedTileLayer, event.mTileId);
break;
}
}
......
package org.libreoffice;
import org.mozilla.gecko.gfx.IntSize;
public class TileIdentifier {
public final int x;
public final int y;
public final float zoom;
public final IntSize size;
public TileIdentifier(int x, int y, float zoom) {
public TileIdentifier(int x, int y, float zoom, IntSize size) {
this.x = x;
this.y = y;
this.zoom = zoom;
this.size = size;
}
@Override
......
package org.mozilla.gecko.gfx;
import android.graphics.RectF;
import android.graphics.Region;
import android.util.Log;
import org.libreoffice.LOEventFactory;
import org.libreoffice.LOKitShell;
import org.libreoffice.TileIdentifier;
import org.mozilla.gecko.util.FloatUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
public abstract class ComposedTileLayer extends Layer {
private static final String LOGTAG = ComposedTileLayer.class.getSimpleName();
protected final List<SubTile> tiles = new CopyOnWriteArrayList<SubTile>();
protected final IntSize tileSize;
protected RectF currentViewport = new RectF();
protected float currentZoom;
public ComposedTileLayer() {
this.tileSize = new IntSize(256, 256);
}
public ComposedTileLayer(IntSize tileSize) {
this.tileSize = tileSize;
}
public void invalidate() {
for (SubTile tile : tiles) {
tile.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);
for (SubTile tile : tiles) {
tile.beginTransaction();
tile.refreshTileMetrics();
tile.endTransaction();
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 RectF roundToTileSize(RectF input, IntSize 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, IntSize 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;
}
private RectF normalizeRect(RectF rect, float factor) {
RectF normalizedRect = new RectF(
rect.left / factor,
rect.top / factor,
rect.right / factor,
rect.bottom / factor);
return normalizedRect;
}
public void reevaluateTiles(ImmutableViewportMetrics viewportMetrics) {
RectF newCurrentViewPort = inflate(roundToTileSize(viewportMetrics.getViewport(), tileSize), tileSize);
float newZoom = viewportMetrics.zoomFactor;
if (!currentViewport.equals(newCurrentViewPort) || currentZoom != newZoom) {
currentViewport = newCurrentViewPort;
currentZoom = newZoom;
RectF normalizedRect = normalizeRect(currentViewport, currentZoom);
RectF normalizedPageRect = normalizeRect(viewportMetrics.getPageRect(), currentZoom);
Log.i(LOGTAG, "reevaluateTiles " + normalizedRect + " " + normalizedPageRect);
clearMarkedTiles();
addNewTiles(viewportMetrics);
markTiles(viewportMetrics);
}
}
private void addNewTiles(ImmutableViewportMetrics viewportMetrics) {
float zoom = getZoom(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.id.x == x && tile.id.y == y && tile.id.zoom == zoom) {
contains = true;
}
}
if (!contains) {
LOKitShell.sendEvent(LOEventFactory.tileRequest(this, new TileIdentifier((int) x, (int) y, zoom, tileSize)));
}
}
}
}
protected abstract float getZoom(ImmutableViewportMetrics viewportMetrics);
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) {
float zoom = getZoom(viewportMetrics);
for (SubTile tile : tiles) {
if (FloatUtils.fuzzyEquals(tile.id.zoom, zoom)) {
RectF tileRect = new RectF(tile.id.x, tile.id.y, tile.id.x + tileSize.width, tile.id.y + tileSize.height);
if (!RectF.intersects(currentViewport, tileRect)) {
tile.markForRemoval();
Log.i(LOGTAG, "Mark for remove - " + currentViewport + " " + tileRect);
}
} else {
Log.i(LOGTAG, "Mark for remove - " + tile.id.zoom + " " + zoom);
tile.markForRemoval();
}
}
}
public void clearAndReset() {
tiles.clear();
currentViewport = new RectF();
}
public void addTile(SubTile tile) {
tile.beginTransaction();
tiles.add(tile);
}
}
\ No newline at end of file
package org.mozilla.gecko.gfx;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
import android.util.Log;
import org.libreoffice.LOEventFactory;
import org.libreoffice.LOKitShell;
import org.libreoffice.TileIdentifier;
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 IntSize tileSize;
private RectF currentViewport = new RectF();
public DynamicTileLayer() {
this.tileSize = new IntSize(256, 256);
}
public DynamicTileLayer(IntSize tileSize) {
this.tileSize = tileSize;
}
public void setTileProvider(TileProvider tileProvider) {
this.tileProvider = tileProvider;
}
public void invalidate() {
for (SubTile tile : tiles) {
tile.invalidate();
}
}
public class DynamicTileLayer extends ComposedTileLayer {
@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.id.x / tile.id.zoom;
float positionY = tile.id.y / tile.id.zoom;
float tileSizeWidth = tileSize.width / tile.id.zoom;
float tileSizeHeight = tileSize.height / tile.id.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, IntSize 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, IntSize 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) {
if (tileProvider == null) {
return;
}
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.id.x == x && tile.id.y == y && tile.id.zoom == viewportMetrics.zoomFactor) {
contains = true;
}
}
if (!contains) {
LOKitShell.sendEvent(LOEventFactory.tileRequest(new TileIdentifier((int)x, (int)y, viewportMetrics.zoomFactor)));
}
}
}
}
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.id.zoom, viewportMetrics.zoomFactor)) {
RectF tileRect = new RectF(tile.id.x, tile.id.y, tile.id.x + tileSize.width, tile.id.y + tileSize.height);
if (!RectF.intersects(currentViewport, tileRect)) {
tile.markForRemoval();
}
} else {
tile.markForRemoval();
}
}
}
public void clearAndReset() {
tiles.clear();
currentViewport = new RectF();
}
public void addTile(TileIdentifier tileId) {
CairoImage image = tileProvider.createTile(tileId.x, tileId.y, tileSize, tileId.zoom);
SubTile tile = new SubTile(image, tileId);
tile.beginTransaction();
tiles.add(tile);
protected float getZoom(ImmutableViewportMetrics viewportMetrics) {
return viewportMetrics.zoomFactor;
}
}
......@@ -15,8 +15,6 @@ import android.util.Log;
import org.libreoffice.LOEvent;
import org.libreoffice.LOEventFactory;
import org.libreoffice.LOKitShell;
import org.libreoffice.TileIdentifier;
import org.libreoffice.TileProvider;
import org.mozilla.gecko.ZoomConstraints;
import org.mozilla.gecko.util.FloatUtils;
......@@ -35,7 +33,7 @@ public class GeckoLayerClient implements PanZoomTarget, LayerView.Listener {
private boolean mRecordDrawTimes;
private final DrawTimingQueue mDrawTimingQueue;
private DynamicTileLayer mRootLayer;
private ComposedTileLayer mRootLayer;
/* The Gecko viewport as per the UI thread. Must be touched only on the UI thread.
* If any events being sent to Gecko that are relative to the Gecko viewport position,
......@@ -228,7 +226,7 @@ public class GeckoLayerClient implements PanZoomTarget, LayerView.Listener {
mDrawTimingQueue.add(displayPort);
}
LOKitShell.sendEvent(LOEventFactory.viewport(clampedMetrics));
reevaluateTiles();
}
/**
......@@ -472,10 +470,6 @@ public class GeckoLayerClient implements PanZoomTarget, LayerView.Listener {
}
/* Root Layer Access */
public void setTileProvider(TileProvider tileProvider) {
mRootLayer.setTileProvider(tileProvider);
}
public void reevaluateTiles() {
mRootLayer.reevaluateTiles(getViewportMetrics());
}
......@@ -483,9 +477,4 @@ public class GeckoLayerClient implements PanZoomTarget, LayerView.Listener {
public void clearAndResetlayers() {
mRootLayer.clearAndReset();
}
public void addTile(TileIdentifier tileId) {
mRootLayer.addTile(tileId);
}
}
\ No newline at end of file
......@@ -5,6 +5,8 @@
package org.mozilla.gecko.gfx;
import android.graphics.Rect;
import org.libreoffice.TileIdentifier;
public class SubTile extends SingleTileLayer {
......@@ -16,6 +18,16 @@ public class SubTile extends SingleTileLayer {
this.id = id;
}
public void refreshTileMetrics() {
Rect position = getPosition();
float positionX = id.x / id.zoom;
float positionY = id.y / id.zoom;
float tileSizeWidth = id.size.width / id.zoom;
float tileSizeHeight = id.size.height / id.zoom;
position.set((int) positionX, (int) positionY, (int) (positionX + tileSizeWidth), (int) (positionY + tileSizeHeight));
setPosition(position);
}
public void markForRemoval() {
markedForRemoval = true;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment