mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-01-27 07:34:20 +00:00
Bug 724230 - Backout ondemand tiling. r=blassey, kats
This backs out changes d8fc13006aa4, ddde7a49f6f7, 34b1cc9454d2 and 8919c54229e1, leaving in some initialisation fixes that were introduced when rebasing. This work may be re-applied at a later date.
This commit is contained in:
parent
244e89d4f2
commit
6a02ed7ca5
@ -77,7 +77,7 @@ public class GeckoEvent {
|
||||
public static final int SAVE_STATE = 18;
|
||||
public static final int BROADCAST = 19;
|
||||
public static final int VIEWPORT = 20;
|
||||
public static final int VISTITED = 21;
|
||||
public static final int VISITED = 21;
|
||||
public static final int NETWORK_CHANGED = 22;
|
||||
|
||||
public static final int IME_COMPOSITION_END = 0;
|
||||
|
@ -90,9 +90,6 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL
|
||||
/* The viewport that Gecko will display when drawing is finished */
|
||||
private ViewportMetrics mNewGeckoViewport;
|
||||
|
||||
/* The offset used to make sure tiles are snapped to the pixel grid */
|
||||
private Point mRenderOffset;
|
||||
|
||||
private CairoImage mCairoImage;
|
||||
|
||||
private static final IntSize TILE_SIZE = new IntSize(256, 256);
|
||||
@ -123,7 +120,6 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL
|
||||
mScreenSize = new IntSize(0, 0);
|
||||
mBufferSize = new IntSize(0, 0);
|
||||
mFormat = CairoImage.FORMAT_RGB16_565;
|
||||
mRenderOffset = new Point(0, 0);
|
||||
|
||||
mCairoImage = new CairoImage() {
|
||||
@Override
|
||||
@ -179,7 +175,6 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL
|
||||
if (mHasDirectTexture) {
|
||||
Log.i(LOGTAG, "Creating WidgetTileLayer");
|
||||
mTileLayer = new WidgetTileLayer(mCairoImage);
|
||||
mRenderOffset.set(0, 0);
|
||||
} else {
|
||||
Log.i(LOGTAG, "Creating MultiTileLayer");
|
||||
mTileLayer = new MultiTileLayer(mCairoImage, TILE_SIZE);
|
||||
@ -195,10 +190,7 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL
|
||||
}
|
||||
|
||||
public boolean beginDrawing(int width, int height, int tileWidth, int tileHeight, String metadata, boolean hasDirectTexture) {
|
||||
// If we've changed surface types, cancel this draw
|
||||
if (setHasDirectTexture(hasDirectTexture)) {
|
||||
return false;
|
||||
}
|
||||
setHasDirectTexture(hasDirectTexture);
|
||||
|
||||
// Make sure the tile-size matches. If it doesn't, we could crash trying
|
||||
// to access invalid memory.
|
||||
@ -231,43 +223,18 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL
|
||||
|
||||
beginTransaction(mTileLayer);
|
||||
|
||||
// We only need to set a render offset/allocate buffer memory if
|
||||
// we're using MultiTileLayer. Otherwise, just synchronise the
|
||||
// buffer size and return.
|
||||
if (!(mTileLayer instanceof MultiTileLayer)) {
|
||||
if (mBufferSize.width != width || mBufferSize.height != height)
|
||||
mBufferSize = new IntSize(width, height);
|
||||
return true;
|
||||
}
|
||||
|
||||
// If the origin has changed, alter the rendering offset so that
|
||||
// rendering is snapped to the tile grid and clear the invalid area.
|
||||
boolean originChanged = true;
|
||||
Point origin = PointUtils.round(mNewGeckoViewport.getDisplayportOrigin());
|
||||
|
||||
if (mGeckoViewport != null) {
|
||||
Point oldOrigin = PointUtils.round(mGeckoViewport.getDisplayportOrigin());
|
||||
originChanged = !origin.equals(oldOrigin);
|
||||
}
|
||||
|
||||
if (originChanged) {
|
||||
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);
|
||||
}
|
||||
|
||||
// If the window size has changed, reallocate the buffer to match.
|
||||
// Synchronise the buffer size with Gecko.
|
||||
if (mBufferSize.width != width || mBufferSize.height != height) {
|
||||
mBufferSize = new IntSize(width, height);
|
||||
|
||||
// We over-allocate to allow for the render offset. nsWindow
|
||||
// assumes that this will happen.
|
||||
IntSize realBufferSize = new IntSize(width + TILE_SIZE.width,
|
||||
height + TILE_SIZE.height);
|
||||
// We only need to allocate buffer memory if we're using MultiTileLayer.
|
||||
if (!(mTileLayer instanceof MultiTileLayer)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Reallocate the buffer if necessary
|
||||
int bpp = CairoUtils.bitsPerPixelForCairoFormat(mFormat) / 8;
|
||||
int size = realBufferSize.getArea() * bpp;
|
||||
int size = mBufferSize.getArea() * bpp;
|
||||
if (mBuffer == null || mBuffer.capacity() != size) {
|
||||
// Free the old buffer
|
||||
if (mBuffer != null) {
|
||||
@ -320,9 +287,7 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL
|
||||
|
||||
if (mTileLayer instanceof MultiTileLayer) {
|
||||
Rect rect = new Rect(x, y, x + width, y + height);
|
||||
rect.offset(mRenderOffset.x, mRenderOffset.y);
|
||||
((MultiTileLayer)mTileLayer).invalidate(rect);
|
||||
((MultiTileLayer)mTileLayer).setRenderOffset(mRenderOffset);
|
||||
}
|
||||
} finally {
|
||||
endTransaction(mTileLayer);
|
||||
@ -348,19 +313,23 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL
|
||||
ByteBuffer tileBuffer = mBuffer.slice();
|
||||
int bpp = CairoUtils.bitsPerPixelForCairoFormat(mFormat) / 8;
|
||||
|
||||
for (int y = 0; y <= mBufferSize.height; y += TILE_SIZE.height) {
|
||||
for (int x = 0; x <= mBufferSize.width; x += TILE_SIZE.width) {
|
||||
for (int y = 0; y < mBufferSize.height; y += TILE_SIZE.height) {
|
||||
for (int x = 0; x < mBufferSize.width; x += TILE_SIZE.width) {
|
||||
// Calculate tile size
|
||||
IntSize tileSize = new IntSize(Math.min(mBufferSize.width - x, TILE_SIZE.width),
|
||||
Math.min(mBufferSize.height - y, TILE_SIZE.height));
|
||||
|
||||
// Create a Bitmap from this tile
|
||||
Bitmap tile = Bitmap.createBitmap(TILE_SIZE.width, TILE_SIZE.height,
|
||||
Bitmap tile = Bitmap.createBitmap(tileSize.width, tileSize.height,
|
||||
CairoUtils.cairoFormatTobitmapConfig(mFormat));
|
||||
tile.copyPixelsFromBuffer(tileBuffer.asIntBuffer());
|
||||
|
||||
// Copy the tile to the master Bitmap and recycle it
|
||||
c.drawBitmap(tile, x - mRenderOffset.x, y - mRenderOffset.y, null);
|
||||
c.drawBitmap(tile, x, y, null);
|
||||
tile.recycle();
|
||||
|
||||
// Progress the buffer to the next tile
|
||||
tileBuffer.position(TILE_SIZE.getArea() * bpp);
|
||||
tileBuffer.position(tileSize.getArea() * bpp);
|
||||
tileBuffer = tileBuffer.slice();
|
||||
}
|
||||
}
|
||||
@ -402,10 +371,6 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL
|
||||
return mBuffer;
|
||||
}
|
||||
|
||||
public Point getRenderOffset() {
|
||||
return mRenderOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gecko calls this function to signal that it is done with the back buffer. After this call,
|
||||
* it is forbidden for Gecko to touch the buffer.
|
||||
|
@ -65,31 +65,23 @@ public abstract class Layer {
|
||||
|
||||
/**
|
||||
* Updates the layer. This returns false if there is still work to be done
|
||||
* after this update. If the layer is not already in a transaction, the
|
||||
* lock will be acquired and a transaction will automatically begin and
|
||||
* end around the update.
|
||||
* after this update.
|
||||
*/
|
||||
public final boolean update(GL10 gl, RenderContext context) {
|
||||
boolean startTransaction = true;
|
||||
if (mTransactionLock.isHeldByCurrentThread()) {
|
||||
startTransaction = false;
|
||||
throw new RuntimeException("draw() called while transaction lock held by this " +
|
||||
"thread?!");
|
||||
}
|
||||
|
||||
// If we're not already in a transaction and we can't acquire the lock,
|
||||
// bail out.
|
||||
if (startTransaction && !mTransactionLock.tryLock()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mInTransaction = true;
|
||||
try {
|
||||
return performUpdates(gl, context);
|
||||
} finally {
|
||||
if (startTransaction) {
|
||||
mInTransaction = false;
|
||||
if (mTransactionLock.tryLock()) {
|
||||
try {
|
||||
return performUpdates(gl, context);
|
||||
} finally {
|
||||
mTransactionLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Subclasses override this function to draw the layer. */
|
||||
@ -128,6 +120,7 @@ public abstract class Layer {
|
||||
mTransactionLock.lock();
|
||||
mView = aView;
|
||||
mInTransaction = true;
|
||||
mNewResolution = mResolution;
|
||||
}
|
||||
|
||||
public void beginTransaction() {
|
||||
|
@ -118,30 +118,12 @@ public class LayerRenderer implements GLSurfaceView.Renderer {
|
||||
|
||||
CairoImage backgroundImage = new BufferedCairoImage(controller.getBackgroundPattern());
|
||||
mBackgroundLayer = new SingleTileLayer(true, backgroundImage);
|
||||
mBackgroundLayer.beginTransaction(null);
|
||||
try {
|
||||
mBackgroundLayer.invalidate();
|
||||
} finally {
|
||||
mBackgroundLayer.endTransaction();
|
||||
}
|
||||
|
||||
mCheckerboardImage = new CheckerboardImage();
|
||||
mCheckerboardLayer = new SingleTileLayer(true, mCheckerboardImage);
|
||||
mCheckerboardLayer.beginTransaction(null);
|
||||
try {
|
||||
mCheckerboardLayer.invalidate();
|
||||
} finally {
|
||||
mCheckerboardLayer.endTransaction();
|
||||
}
|
||||
|
||||
CairoImage shadowImage = new BufferedCairoImage(controller.getShadowPattern());
|
||||
mShadowLayer = new NinePatchTileLayer(shadowImage);
|
||||
mShadowLayer.beginTransaction(null);
|
||||
try {
|
||||
mShadowLayer.invalidate();
|
||||
} finally {
|
||||
mShadowLayer.endTransaction();
|
||||
}
|
||||
|
||||
IntSize frameRateLayerSize = new IntSize(FRAME_RATE_METER_WIDTH, FRAME_RATE_METER_HEIGHT);
|
||||
mFrameRateLayer = TextLayer.create(frameRateLayerSize, "-- ms/--");
|
||||
|
@ -37,21 +37,16 @@
|
||||
|
||||
package org.mozilla.gecko.gfx;
|
||||
|
||||
import org.mozilla.gecko.FloatUtils;
|
||||
import org.mozilla.gecko.gfx.CairoImage;
|
||||
import org.mozilla.gecko.gfx.IntSize;
|
||||
import org.mozilla.gecko.gfx.SingleTileLayer;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.Region;
|
||||
import android.util.Log;
|
||||
import java.lang.Long;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.ListIterator;
|
||||
import java.util.ArrayList;
|
||||
import javax.microedition.khronos.opengles.GL10;
|
||||
|
||||
/**
|
||||
@ -63,18 +58,9 @@ public class MultiTileLayer extends Layer {
|
||||
private static final String LOGTAG = "GeckoMultiTileLayer";
|
||||
|
||||
private final CairoImage mImage;
|
||||
private final IntSize mTileSize;
|
||||
private 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;
|
||||
private final ArrayList<SubTile> mTiles;
|
||||
|
||||
public MultiTileLayer(CairoImage image, IntSize tileSize) {
|
||||
super();
|
||||
@ -82,38 +68,29 @@ public class MultiTileLayer extends Layer {
|
||||
mImage = image;
|
||||
mTileSize = tileSize;
|
||||
mBufferSize = new IntSize(0, 0);
|
||||
mDirtyRegion = new Region();
|
||||
mValidRegion = new Region();
|
||||
mRenderOffset = new Point();
|
||||
mTiles = new LinkedList<SubTile>();
|
||||
mPositionHash = new HashMap<Long, SubTile>();
|
||||
mTiles = new ArrayList<SubTile>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates a sub-region of the layer. Data will be uploaded from the
|
||||
* backing buffer over subsequent calls to update().
|
||||
* This method is only valid inside a transaction.
|
||||
*/
|
||||
public void invalidate(Rect dirtyRect) {
|
||||
if (!inTransaction()) {
|
||||
throw new RuntimeException("invalidate() is only valid inside a transaction");
|
||||
}
|
||||
|
||||
mDirtyRegion.union(dirtyRect);
|
||||
mValidRegion.union(dirtyRect);
|
||||
for (SubTile layer : mTiles) {
|
||||
IntSize tileSize = layer.getSize();
|
||||
Rect tileRect = new Rect(layer.x, layer.y, layer.x + tileSize.width, layer.y + tileSize.height);
|
||||
|
||||
if (tileRect.intersect(dirtyRect)) {
|
||||
tileRect.offset(-layer.x, -layer.y);
|
||||
layer.invalidate(tileRect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates the backing buffer. Data will not be uploaded from an invalid
|
||||
* backing buffer. This method is only valid inside a transaction.
|
||||
*/
|
||||
protected void invalidateBuffer() {
|
||||
if (!inTransaction()) {
|
||||
throw new RuntimeException("invalidateBuffer() is only valid inside a transaction");
|
||||
public void invalidate() {
|
||||
for (SubTile layer : mTiles) {
|
||||
layer.invalidate();
|
||||
}
|
||||
|
||||
mDirtyRegion.setEmpty();
|
||||
mValidRegion.setEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -121,109 +98,62 @@ public class MultiTileLayer extends Layer {
|
||||
return mImage.getSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes sure there are enough tiles to accommodate the buffer image.
|
||||
*/
|
||||
private void validateTiles() {
|
||||
IntSize size = getSize();
|
||||
|
||||
if (size.equals(mBufferSize))
|
||||
if (size.equals(mBufferSize)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Regenerate tiles
|
||||
mTiles.clear();
|
||||
int offset = 0;
|
||||
final int format = mImage.getFormat();
|
||||
final ByteBuffer buffer = mImage.getBuffer().slice();
|
||||
final int bpp = CairoUtils.bitsPerPixelForCairoFormat(format) / 8;
|
||||
for (int y = 0; y < size.height; y += mTileSize.height) {
|
||||
for (int x = 0; x < size.width; x += mTileSize.width) {
|
||||
// Create a CairoImage implementation that returns a
|
||||
// tile from the parent CairoImage. It's assumed that
|
||||
// the tiles are stored in series.
|
||||
final IntSize layerSize =
|
||||
new IntSize(Math.min(mTileSize.width, size.width - x),
|
||||
Math.min(mTileSize.height, size.height - y));
|
||||
final int tileOffset = offset;
|
||||
|
||||
CairoImage subImage = new CairoImage() {
|
||||
@Override
|
||||
public ByteBuffer getBuffer() {
|
||||
// Create a ByteBuffer that shares the data of the original
|
||||
// buffer, but is positioned and limited so that only the
|
||||
// tile data is accessible.
|
||||
buffer.position(tileOffset);
|
||||
ByteBuffer tileBuffer = buffer.slice();
|
||||
tileBuffer.limit(layerSize.getArea() * bpp);
|
||||
|
||||
return tileBuffer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntSize getSize() {
|
||||
return layerSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFormat() {
|
||||
return format;
|
||||
}
|
||||
};
|
||||
|
||||
mTiles.add(new SubTile(subImage, x, y));
|
||||
offset += layerSize.getArea() * bpp;
|
||||
}
|
||||
}
|
||||
|
||||
// Set tile origins and resolution
|
||||
refreshTileMetrics(getOrigin(), getResolution(), false);
|
||||
|
||||
mBufferSize = size;
|
||||
|
||||
// Shrink/grow tile pool
|
||||
int nTiles = (Math.round(size.width / (float)mTileSize.width) + 1) *
|
||||
(Math.round(size.height / (float)mTileSize.height) + 1);
|
||||
if (mTiles.size() < nTiles) {
|
||||
Log.i(LOGTAG, "Tile pool growing from " + mTiles.size() + " to " + nTiles);
|
||||
|
||||
for (int i = 0; i < nTiles; i++) {
|
||||
mTiles.add(new SubTile(new SubImage(mImage, mTileSize)));
|
||||
}
|
||||
} else if (mTiles.size() > nTiles) {
|
||||
Log.i(LOGTAG, "Tile pool shrinking from " + mTiles.size() + " to " + nTiles);
|
||||
|
||||
// Remove tiles from the beginning of the list, as these are
|
||||
// least recently used tiles
|
||||
for (int i = mTiles.size(); i > nTiles; i--) {
|
||||
SubTile tile = mTiles.get(0);
|
||||
if (tile.key != null) {
|
||||
mPositionHash.remove(tile.key);
|
||||
}
|
||||
mTiles.remove(0);
|
||||
}
|
||||
}
|
||||
|
||||
// A buffer size probably means a layout change, so invalidate all tiles.
|
||||
invalidateTiles();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Long representing the given Point. Used for hashing.
|
||||
*/
|
||||
private Long longFromPoint(Point point) {
|
||||
// Assign 32 bits for each dimension of the point.
|
||||
return new Long((((long)point.x) << 32) | point.y);
|
||||
}
|
||||
|
||||
private Point getOffsetOrigin() {
|
||||
Point origin = new Point(getOrigin());
|
||||
origin.offset(-mRenderOffset.x, -mRenderOffset.y);
|
||||
return origin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the necessary functions to update the specified properties of
|
||||
* a sub-tile.
|
||||
*/
|
||||
private void updateTile(GL10 gl, RenderContext context, SubTile tile, Point tileOrigin, Rect dirtyRect, boolean reused) {
|
||||
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();
|
||||
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.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.
|
||||
tile.invalidateTexture();
|
||||
|
||||
// (Re)Place in the position hash for quick retrieval.
|
||||
if (tile.key != null) {
|
||||
mPositionHash.remove(tile.key);
|
||||
}
|
||||
tile.key = longFromPoint(tileOrigin);
|
||||
mPositionHash.put(tile.key, tile);
|
||||
}
|
||||
|
||||
// Invalidate the area we want to upload.
|
||||
tile.invalidate(dirtyRect);
|
||||
|
||||
// Perform updates and mark texture as valid.
|
||||
if (!tile.performUpdates(gl, context)) {
|
||||
Log.e(LOGTAG, "Sub-tile failed to update fully");
|
||||
}
|
||||
} finally {
|
||||
tile.endTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -232,154 +162,86 @@ public class MultiTileLayer extends Layer {
|
||||
|
||||
validateTiles();
|
||||
|
||||
// Bail out early if we have nothing to do.
|
||||
if (mDirtyRegion.isEmpty() || mTiles.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
// 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.
|
||||
boolean invalid = layer.getSkipTextureUpdate();
|
||||
layer.setSkipTextureUpdate(true);
|
||||
layer.performUpdates(gl, context);
|
||||
|
||||
// Check that we're capable of updating from this origin.
|
||||
Point origin = getOffsetOrigin();
|
||||
if ((origin.x % mTileSize.width) != 0 || (origin.y % mTileSize.height) != 0) {
|
||||
Log.e(LOGTAG, "MultiTileLayer doesn't support non tile-aligned buffers! (" +
|
||||
origin.x + ", " + origin.y + ")");
|
||||
return true;
|
||||
}
|
||||
RectF layerBounds = layer.getBounds(context, new FloatSize(layer.getSize()));
|
||||
boolean isDirty = layer.isDirty();
|
||||
|
||||
// Transform the viewport into tile-space so we can see what part of the
|
||||
// dirty region intersects with it.
|
||||
// We update any tiles intersecting with the screen before tiles
|
||||
// intersecting with the viewport.
|
||||
// XXX Maybe we want to to split this update even further to update
|
||||
// checkerboard area before updating screen regions with old data.
|
||||
// Note that this could provide inconsistent views, so we may not
|
||||
// want to do this.
|
||||
Rect tilespaceViewport;
|
||||
float scaleFactor = getResolution() / context.zoomFactor;
|
||||
tilespaceViewport = RectUtils.roundOut(RectUtils.scale(context.viewport, scaleFactor));
|
||||
tilespaceViewport.offset(-origin.x, -origin.y);
|
||||
|
||||
// Expand tile-space viewport to tile boundaries
|
||||
tilespaceViewport.left = (tilespaceViewport.left / mTileSize.width) * mTileSize.width;
|
||||
tilespaceViewport.right += mTileSize.width - 1;
|
||||
tilespaceViewport.right = (tilespaceViewport.right / mTileSize.width) * mTileSize.width;
|
||||
tilespaceViewport.top = (tilespaceViewport.top / mTileSize.height) * mTileSize.height;
|
||||
tilespaceViewport.bottom += mTileSize.height - 1;
|
||||
tilespaceViewport.bottom = (tilespaceViewport.bottom / mTileSize.height) * mTileSize.height;
|
||||
|
||||
// Declare a region for storing the results of Region operations
|
||||
Region opRegion = new Region();
|
||||
|
||||
// Test if the dirty region intersects with the screen
|
||||
boolean updateVisible = false;
|
||||
Region updateRegion = mDirtyRegion;
|
||||
if (opRegion.op(tilespaceViewport, mDirtyRegion, Region.Op.INTERSECT)) {
|
||||
updateVisible = true;
|
||||
updateRegion = new Region(opRegion);
|
||||
}
|
||||
|
||||
// Invalidate any tiles that are due to be replaced if their resolution
|
||||
// doesn't match the parent layer resolution, and any tiles that are
|
||||
// off-screen and off-buffer, as we cannot guarantee their validity.
|
||||
//
|
||||
// Note that we also cannot guarantee the validity of on-screen,
|
||||
// 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>();
|
||||
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 ((!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();
|
||||
|
||||
// Remove from the position hash
|
||||
mPositionHash.remove(tile.key);
|
||||
tile.key = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Push invalid tiles to the head of the queue so they get used first
|
||||
mTiles.addAll(0, invalidTiles);
|
||||
|
||||
// Update tiles
|
||||
// Note, it's <= as the buffer is over-allocated due to render-offsetting.
|
||||
for (int y = origin.y; y <= origin.y + mBufferSize.height; y += mTileSize.height) {
|
||||
for (int x = origin.x; x <= origin.x + mBufferSize.width; x += mTileSize.width) {
|
||||
// Does this tile intersect with the dirty region?
|
||||
Rect tilespaceTileRect = new Rect(x - origin.x, y - origin.y,
|
||||
(x - origin.x) + mTileSize.width,
|
||||
(y - origin.y) + mTileSize.height);
|
||||
if (!opRegion.op(tilespaceTileRect, updateRegion, Region.Op.INTERSECT)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Dirty tile, find out if we already have this tile to reuse.
|
||||
boolean reusedTile;
|
||||
Point tileOrigin = new Point(x, y);
|
||||
SubTile tile = mPositionHash.get(longFromPoint(tileOrigin));
|
||||
|
||||
// If we don't, get an unused tile (we store these at the head of the list).
|
||||
if (tile == null) {
|
||||
tile = mTiles.removeFirst();
|
||||
reusedTile = false;
|
||||
if (isDirty) {
|
||||
if (!RectF.intersects(layerBounds, context.viewport)) {
|
||||
if (firstDirtyTile == null)
|
||||
firstDirtyTile = layer;
|
||||
dirtyTiles ++;
|
||||
invalid = true;
|
||||
} 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.
|
||||
mTiles.add(tile);
|
||||
|
||||
// Work out the tile's invalid area in this tile's space.
|
||||
if (opRegion.isComplex()) {
|
||||
Log.w(LOGTAG, "MultiTileLayer encountered complex dirty region");
|
||||
}
|
||||
Rect dirtyRect = opRegion.getBounds();
|
||||
dirtyRect.offset(origin.x - x, origin.y - y);
|
||||
|
||||
// Update tile metrics and texture data
|
||||
tile.x = (x - origin.x) / mTileSize.width;
|
||||
tile.y = (y - origin.y) / mTileSize.height;
|
||||
updateTile(gl, context, tile, tileOrigin, dirtyRect, reusedTile);
|
||||
|
||||
// If this update isn't visible, we only want to update one
|
||||
// tile at a time.
|
||||
if (!updateVisible) {
|
||||
mDirtyRegion.op(opRegion, Region.Op.XOR);
|
||||
return mDirtyRegion.isEmpty();
|
||||
// This tile intersects with the screen and is dirty,
|
||||
// update it immediately.
|
||||
layer.setSkipTextureUpdate(false);
|
||||
screenUpdateDone = true;
|
||||
layer.performUpdates(gl, context);
|
||||
invalid = false;
|
||||
}
|
||||
}
|
||||
|
||||
// We use the SkipTextureUpdate flag as a marker of a tile's
|
||||
// validity. This is required, as sometimes layers are drawn
|
||||
// without updating first, and we mustn't draw tiles that have
|
||||
// been marked as invalid that we haven't updated.
|
||||
layer.setSkipTextureUpdate(invalid);
|
||||
}
|
||||
|
||||
// Remove the update region from the dirty region
|
||||
mDirtyRegion.op(updateRegion, Region.Op.XOR);
|
||||
// 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.setSkipTextureUpdate(false);
|
||||
firstDirtyTile.performUpdates(gl, context);
|
||||
dirtyTiles --;
|
||||
}
|
||||
|
||||
return mDirtyRegion.isEmpty();
|
||||
return (dirtyTiles == 0);
|
||||
}
|
||||
|
||||
private void refreshTileMetrics(Point origin, float resolution, boolean inTransaction) {
|
||||
IntSize size = getSize();
|
||||
for (SubTile layer : mTiles) {
|
||||
if (!inTransaction) {
|
||||
layer.beginTransaction(null);
|
||||
}
|
||||
|
||||
if (origin != null) {
|
||||
layer.setOrigin(new Point(origin.x + layer.x, origin.y + layer.y));
|
||||
}
|
||||
if (resolution >= 0.0f) {
|
||||
layer.setResolution(resolution);
|
||||
}
|
||||
|
||||
if (!inTransaction) {
|
||||
layer.endTransaction();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOrigin(Point newOrigin) {
|
||||
super.setOrigin(newOrigin);
|
||||
refreshTileMetrics(newOrigin, -1, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResolution(float newResolution) {
|
||||
super.setResolution(newResolution);
|
||||
refreshTileMetrics(null, newResolution, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -403,46 +265,23 @@ public class MultiTileLayer extends Layer {
|
||||
@Override
|
||||
public void draw(RenderContext context) {
|
||||
for (SubTile layer : mTiles) {
|
||||
// Skip invalid tiles
|
||||
if (layer.key == null) {
|
||||
// We use the SkipTextureUpdate flag as a validity flag. If it's false,
|
||||
// the contents of this tile are invalid and we shouldn't draw it.
|
||||
if (layer.getSkipTextureUpdate())
|
||||
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) {
|
||||
if (mOrigin == null || !origin.equals(mOrigin)) {
|
||||
mOrigin = origin;
|
||||
super.setOrigin(origin);
|
||||
invalidateBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResolution(float resolution) {
|
||||
if (!FloatUtils.fuzzyEquals(resolution, mResolution)) {
|
||||
mResolution = resolution;
|
||||
super.setResolution(resolution);
|
||||
invalidateBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
public void setRenderOffset(Point offset) {
|
||||
mRenderOffset.set(offset.x, offset.y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Region getValidRegion(RenderContext context) {
|
||||
Region validRegion = new Region();
|
||||
for (SubTile tile : mTiles) {
|
||||
if (tile.key == null || tile.getValidTextureArea().isEmpty())
|
||||
if (tile.getSkipTextureUpdate())
|
||||
continue;
|
||||
validRegion.op(tile.getValidRegion(context), Region.Op.UNION);
|
||||
}
|
||||
@ -450,90 +289,14 @@ public class MultiTileLayer extends Layer {
|
||||
return validRegion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates all sub-tiles. This should be called if the source backing
|
||||
* this layer has changed. This method is only valid inside a transaction.
|
||||
*/
|
||||
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);
|
||||
tile.key = null;
|
||||
}
|
||||
tile.invalidateTexture();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A SingleTileLayer extension with fields for relevant tile data that
|
||||
* MultiTileLayer requires.
|
||||
*/
|
||||
private static class SubTile extends SingleTileLayer {
|
||||
class SubTile extends SingleTileLayer {
|
||||
public int x;
|
||||
public int y;
|
||||
|
||||
public Long key;
|
||||
|
||||
public SubTile(SubImage aImage) {
|
||||
super(aImage);
|
||||
|
||||
aImage.tile = this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A CairoImage implementation that returns a tile from a parent CairoImage.
|
||||
* This assumes that the parent image has a size that is a multiple of the
|
||||
* tile size.
|
||||
*/
|
||||
private static class SubImage extends CairoImage {
|
||||
public SubTile tile;
|
||||
|
||||
private IntSize mTileSize;
|
||||
private CairoImage mImage;
|
||||
|
||||
public SubImage(CairoImage image, IntSize tileSize) {
|
||||
mTileSize = tileSize;
|
||||
mImage = image;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer getBuffer() {
|
||||
// Create a ByteBuffer that shares the data of the original
|
||||
// buffer, but is positioned and limited so that only the
|
||||
// tile data is accessible.
|
||||
IntSize bufferSize = mImage.getSize();
|
||||
int bpp = CairoUtils.bitsPerPixelForCairoFormat(getFormat()) / 8;
|
||||
int index = (tile.y * (bufferSize.width / mTileSize.width + 1)) + tile.x;
|
||||
|
||||
ByteBuffer buffer = mImage.getBuffer().slice();
|
||||
|
||||
try {
|
||||
buffer.position(index * mTileSize.getArea() * bpp);
|
||||
buffer = buffer.slice();
|
||||
buffer.limit(mTileSize.getArea() * bpp);
|
||||
} catch (IllegalArgumentException e) {
|
||||
Log.e(LOGTAG, "Tile image-data out of bounds! Tile: (" +
|
||||
tile.x + ", " + tile.y + "), image (" + bufferSize + ")");
|
||||
return null;
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntSize getSize() {
|
||||
return mTileSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFormat() {
|
||||
return mImage.getFormat();
|
||||
public SubTile(CairoImage mImage, int mX, int mY) {
|
||||
super(mImage);
|
||||
x = mX;
|
||||
y = mY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -105,12 +105,6 @@ public final class RectUtils {
|
||||
Math.round(rect.right), Math.round(rect.bottom));
|
||||
}
|
||||
|
||||
/** Returns the smallest integer rect that encapsulates the given rect. */
|
||||
public static Rect roundOut(RectF rect) {
|
||||
return new Rect((int)Math.floor(rect.left), (int)Math.floor(rect.top),
|
||||
(int)Math.ceil(rect.right), (int)Math.ceil(rect.bottom));
|
||||
}
|
||||
|
||||
public static IntSize getSize(Rect rect) {
|
||||
return new IntSize(rect.width(), rect.height());
|
||||
}
|
||||
|
@ -43,7 +43,6 @@ import org.mozilla.gecko.gfx.IntSize;
|
||||
import org.mozilla.gecko.gfx.LayerController;
|
||||
import org.mozilla.gecko.gfx.TileLayer;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.opengl.GLES11;
|
||||
import android.opengl.GLES11Ext;
|
||||
@ -59,8 +58,6 @@ import javax.microedition.khronos.opengles.GL10;
|
||||
* TODO: Repeating textures really should be their own type of layer.
|
||||
*/
|
||||
public class SingleTileLayer extends TileLayer {
|
||||
private static final String LOGTAG = "GeckoSingleTileLayer";
|
||||
|
||||
public SingleTileLayer(CairoImage image) { this(false, image); }
|
||||
|
||||
public SingleTileLayer(boolean repeat, CairoImage image) {
|
||||
@ -74,11 +71,6 @@ public class SingleTileLayer extends TileLayer {
|
||||
if (!initialized())
|
||||
return;
|
||||
|
||||
// If the texture contents is entirely invalid, we have nothing to draw.
|
||||
Rect validTexture = getValidTextureArea();
|
||||
if (validTexture.isEmpty())
|
||||
return;
|
||||
|
||||
GLES11.glBindTexture(GL10.GL_TEXTURE_2D, getTextureID());
|
||||
|
||||
RectF bounds;
|
||||
@ -87,27 +79,13 @@ public class SingleTileLayer extends TileLayer {
|
||||
RectF viewport = context.viewport;
|
||||
|
||||
if (repeats()) {
|
||||
if (!validTexture.equals(new Rect(0, 0, size.width, size.height))) {
|
||||
Log.e(LOGTAG, "Drawing partial repeating textures is unsupported!");
|
||||
}
|
||||
|
||||
bounds = new RectF(0.0f, 0.0f, viewport.width(), viewport.height());
|
||||
int width = Math.round(viewport.width());
|
||||
int height = Math.round(-viewport.height());
|
||||
cropRect = new int[] { 0, size.height, width, height };
|
||||
} else {
|
||||
bounds = getBounds(context, new FloatSize(size));
|
||||
|
||||
float scaleFactor = bounds.width() / (float)size.width;
|
||||
bounds.left += validTexture.left * scaleFactor;
|
||||
bounds.top += validTexture.top * scaleFactor;
|
||||
bounds.right -= (size.width - validTexture.right) * scaleFactor;
|
||||
bounds.bottom -= (size.height - validTexture.bottom) * scaleFactor;
|
||||
|
||||
cropRect = new int[] { validTexture.left,
|
||||
validTexture.bottom,
|
||||
validTexture.width(),
|
||||
-validTexture.height() };
|
||||
cropRect = new int[] { 0, size.height, size.width, -size.height };
|
||||
}
|
||||
|
||||
GLES11.glTexParameteriv(GL10.GL_TEXTURE_2D, GLES11Ext.GL_TEXTURE_CROP_RECT_OES, cropRect,
|
||||
|
@ -61,14 +61,14 @@ public abstract class TileLayer extends Layer {
|
||||
private final CairoImage mImage;
|
||||
private final boolean mRepeat;
|
||||
private IntSize mSize;
|
||||
private Rect mValidTextureRect;
|
||||
private boolean mSkipTextureUpdate;
|
||||
private int[] mTextureIDs;
|
||||
|
||||
public TileLayer(boolean repeat, CairoImage image) {
|
||||
mRepeat = repeat;
|
||||
mImage = image;
|
||||
mSize = new IntSize(0, 0);
|
||||
mValidTextureRect = new Rect();
|
||||
mSkipTextureUpdate = false;
|
||||
|
||||
IntSize bufferSize = mImage.getSize();
|
||||
mDirtyRect = new Rect();
|
||||
@ -134,43 +134,23 @@ public abstract class TileLayer extends Layer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells the tile that its texture contents are invalid. This will also
|
||||
* clear any invalidated area.
|
||||
*/
|
||||
public void invalidateTexture() {
|
||||
mValidTextureRect.setEmpty();
|
||||
mDirtyRect.setEmpty();
|
||||
/** Tells the tile not to update the texture on the next update. */
|
||||
public void setSkipTextureUpdate(boolean skip) {
|
||||
mSkipTextureUpdate = skip;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a handle to the valid texture area rectangle. Modifying this
|
||||
* Rect will modify the valid texture area for this layer.
|
||||
*/
|
||||
public Rect getValidTextureArea() {
|
||||
return mValidTextureRect;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Region getValidRegion(RenderContext context) {
|
||||
if (mValidTextureRect.isEmpty())
|
||||
return new Region();
|
||||
|
||||
Point origin = getOrigin();
|
||||
float scaleFactor = context.zoomFactor / getResolution();
|
||||
float x = (origin.x + mValidTextureRect.left) * scaleFactor;
|
||||
float y = (origin.y + mValidTextureRect.top) * scaleFactor;
|
||||
float width = mValidTextureRect.width() * scaleFactor;
|
||||
float height = mValidTextureRect.height() * scaleFactor;
|
||||
|
||||
return new Region(Math.round(x), Math.round(y),
|
||||
Math.round(x + width), Math.round(y + height));
|
||||
public boolean getSkipTextureUpdate() {
|
||||
return mSkipTextureUpdate;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean performUpdates(GL10 gl, RenderContext context) {
|
||||
super.performUpdates(gl, context);
|
||||
|
||||
if (mSkipTextureUpdate) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Reallocate the texture if the size has changed
|
||||
validateTexture(gl);
|
||||
|
||||
@ -178,20 +158,24 @@ public abstract class TileLayer extends Layer {
|
||||
if (!mImage.getSize().isPositive())
|
||||
return true;
|
||||
|
||||
// Update the dirty region
|
||||
uploadDirtyRect(gl, mDirtyRect);
|
||||
// If we haven't allocated a texture, assume the whole region is dirty
|
||||
if (mTextureIDs == null) {
|
||||
uploadFullTexture(gl);
|
||||
} else {
|
||||
uploadDirtyRect(gl, mDirtyRect);
|
||||
}
|
||||
|
||||
mDirtyRect.setEmpty();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void uploadDirtyRect(GL10 gl, Rect dirtyRect) {
|
||||
private void uploadFullTexture(GL10 gl) {
|
||||
IntSize bufferSize = mImage.getSize();
|
||||
Rect bufferRect = new Rect(0, 0, bufferSize.width, bufferSize.height);
|
||||
|
||||
// Make sure the dirty region intersects with the buffer
|
||||
dirtyRect.intersect(bufferRect);
|
||||
uploadDirtyRect(gl, new Rect(0, 0, bufferSize.width, bufferSize.height));
|
||||
}
|
||||
|
||||
private void uploadDirtyRect(GL10 gl, Rect dirtyRect) {
|
||||
// If we have nothing to upload, just return for now
|
||||
if (dirtyRect.isEmpty())
|
||||
return;
|
||||
@ -201,11 +185,6 @@ public abstract class TileLayer extends Layer {
|
||||
if (imageBuffer == null)
|
||||
return;
|
||||
|
||||
// Mark the dirty region as valid. Note, we assume that the valid area
|
||||
// can be enclosed by a rectangle (ideally we'd use a Region, but it'd
|
||||
// be slower and it probably isn't necessary).
|
||||
mValidTextureRect.union(dirtyRect);
|
||||
|
||||
boolean newlyCreated = false;
|
||||
|
||||
if (mTextureIDs == null) {
|
||||
@ -214,12 +193,15 @@ public abstract class TileLayer extends Layer {
|
||||
newlyCreated = true;
|
||||
}
|
||||
|
||||
IntSize bufferSize = mImage.getSize();
|
||||
Rect bufferRect = new Rect(0, 0, bufferSize.width, bufferSize.height);
|
||||
|
||||
int cairoFormat = mImage.getFormat();
|
||||
CairoGLInfo glInfo = new CairoGLInfo(cairoFormat);
|
||||
|
||||
bindAndSetGLParameters(gl);
|
||||
|
||||
if (newlyCreated || dirtyRect.equals(bufferRect)) {
|
||||
if (newlyCreated || dirtyRect.contains(bufferRect)) {
|
||||
if (mSize.equals(bufferSize)) {
|
||||
gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, glInfo.internalFormat, mSize.width, mSize.height,
|
||||
0, glInfo.format, glInfo.type, imageBuffer);
|
||||
@ -233,6 +215,12 @@ public abstract class TileLayer extends Layer {
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure that the dirty region intersects with the buffer rect,
|
||||
// otherwise we'll end up with an invalid buffer pointer.
|
||||
if (!Rect.intersects(dirtyRect, bufferRect)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Upload the changed rect. We have to widen to the full width of the texture
|
||||
* because we can't count on the device having support for GL_EXT_unpack_subimage,
|
||||
@ -249,8 +237,8 @@ public abstract class TileLayer extends Layer {
|
||||
}
|
||||
|
||||
viewBuffer.position(position);
|
||||
gl.glTexSubImage2D(gl.GL_TEXTURE_2D, 0, 0, dirtyRect.top,
|
||||
bufferSize.width, dirtyRect.height(),
|
||||
gl.glTexSubImage2D(gl.GL_TEXTURE_2D, 0, 0, dirtyRect.top, bufferSize.width,
|
||||
Math.min(bufferSize.height - dirtyRect.top, dirtyRect.height()),
|
||||
glInfo.format, glInfo.type, viewBuffer);
|
||||
}
|
||||
|
||||
|
@ -2135,7 +2135,6 @@ Tab.prototype = {
|
||||
// Is it on the top level?
|
||||
let contentDocument = aSubject;
|
||||
if (contentDocument == this.browser.contentDocument) {
|
||||
sendMessageToJava({ gecko: { type: "Document:Shown" } });
|
||||
ViewportHandler.updateMetadata(this);
|
||||
this.documentIdForCurrentViewport = ViewportHandler.getIdForDocument(contentDocument);
|
||||
}
|
||||
|
@ -111,7 +111,6 @@ jmethodID AndroidAddress::jGetThoroughfareMethod;
|
||||
jclass AndroidGeckoSoftwareLayerClient::jGeckoSoftwareLayerClientClass = 0;
|
||||
jmethodID AndroidGeckoSoftwareLayerClient::jLockBufferMethod = 0;
|
||||
jmethodID AndroidGeckoSoftwareLayerClient::jUnlockBufferMethod = 0;
|
||||
jmethodID AndroidGeckoSoftwareLayerClient::jGetRenderOffsetMethod = 0;
|
||||
jmethodID AndroidGeckoSoftwareLayerClient::jBeginDrawingMethod = 0;
|
||||
jmethodID AndroidGeckoSoftwareLayerClient::jEndDrawingMethod = 0;
|
||||
jclass AndroidGeckoSurfaceView::jGeckoSurfaceViewClass = 0;
|
||||
@ -330,7 +329,6 @@ AndroidGeckoSoftwareLayerClient::InitGeckoSoftwareLayerClientClass(JNIEnv *jEnv)
|
||||
|
||||
jLockBufferMethod = getMethod("lockBuffer", "()Ljava/nio/ByteBuffer;");
|
||||
jUnlockBufferMethod = getMethod("unlockBuffer", "()V");
|
||||
jGetRenderOffsetMethod = getMethod("getRenderOffset", "()Landroid/graphics/Point;");
|
||||
jBeginDrawingMethod = getMethod("beginDrawing", "(IIIILjava/lang/String;Z)Z");
|
||||
jEndDrawingMethod = getMethod("endDrawing", "(IIII)V");
|
||||
#endif
|
||||
@ -684,18 +682,6 @@ AndroidGeckoSoftwareLayerClient::UnlockBuffer()
|
||||
env->CallVoidMethod(wrapped_obj, jUnlockBufferMethod);
|
||||
}
|
||||
|
||||
void
|
||||
AndroidGeckoSoftwareLayerClient::GetRenderOffset(nsIntPoint &aOffset)
|
||||
{
|
||||
JNIEnv *env = AndroidBridge::GetJNIEnv();
|
||||
if (!env)
|
||||
return;
|
||||
|
||||
AndroidPoint offset(env, env->CallObjectMethod(wrapped_obj, jGetRenderOffsetMethod));
|
||||
aOffset.x = offset.X();
|
||||
aOffset.y = offset.Y();
|
||||
}
|
||||
|
||||
bool
|
||||
AndroidGeckoSoftwareLayerClient::BeginDrawing(int aWidth, int aHeight, int aTileWidth, int aTileHeight, const nsAString &aMetadata, bool aHasDirectTexture)
|
||||
{
|
||||
|
@ -161,7 +161,6 @@ public:
|
||||
jobject LockBuffer();
|
||||
unsigned char *LockBufferBits();
|
||||
void UnlockBuffer();
|
||||
void GetRenderOffset(nsIntPoint &aOffset);
|
||||
bool BeginDrawing(int aWidth, int aHeight, int aTileWidth, int aTileHeight, const nsAString &aMetadata, bool aHasDirectTexture);
|
||||
void EndDrawing(const nsIntRect &aRect);
|
||||
|
||||
@ -171,7 +170,6 @@ private:
|
||||
static jmethodID jUnlockBufferMethod;
|
||||
|
||||
protected:
|
||||
static jmethodID jGetRenderOffsetMethod;
|
||||
static jmethodID jBeginDrawingMethod;
|
||||
static jmethodID jEndDrawingMethod;
|
||||
};
|
||||
|
@ -1216,9 +1216,6 @@ nsWindow::OnDraw(AndroidGeckoEvent *ae)
|
||||
return;
|
||||
}
|
||||
|
||||
nsIntPoint renderOffset;
|
||||
client.GetRenderOffset(renderOffset);
|
||||
|
||||
nsIntRect dirtyRect = ae->Rect().Intersect(nsIntRect(0, 0, gAndroidBounds.width, gAndroidBounds.height));
|
||||
|
||||
unsigned char *bits = NULL;
|
||||
@ -1241,26 +1238,24 @@ nsWindow::OnDraw(AndroidGeckoEvent *ae)
|
||||
|
||||
int offset = 0;
|
||||
|
||||
// It is assumed that the buffer has been over-allocated so that not
|
||||
// only is the tile-size constant, but that a render-offset of anything
|
||||
// up to (but not including) the tile size could be accommodated.
|
||||
for (int y = 0; y < gAndroidBounds.height + gAndroidTileSize.height; y += tileHeight) {
|
||||
for (int x = 0; x < gAndroidBounds.width + gAndroidTileSize.width; x += tileWidth) {
|
||||
for (int y = 0; y < gAndroidBounds.height; y += tileHeight) {
|
||||
for (int x = 0; x < gAndroidBounds.width; x += tileWidth) {
|
||||
int width = NS_MIN(tileWidth, gAndroidBounds.width - x);
|
||||
int height = NS_MIN(tileHeight, gAndroidBounds.height - y);
|
||||
|
||||
nsRefPtr<gfxImageSurface> targetSurface =
|
||||
new gfxImageSurface(bits + offset,
|
||||
gfxIntSize(tileWidth, tileHeight),
|
||||
tileWidth * 2,
|
||||
gfxIntSize(width, height),
|
||||
width * 2,
|
||||
gfxASurface::ImageFormatRGB16_565);
|
||||
|
||||
offset += tileWidth * tileHeight * 2;
|
||||
offset += width * height * 2;
|
||||
|
||||
if (targetSurface->CairoStatus()) {
|
||||
ALOG("### Failed to create a valid surface from the bitmap");
|
||||
break;
|
||||
} else {
|
||||
targetSurface->SetDeviceOffset(gfxPoint(renderOffset.x - x,
|
||||
renderOffset.y - y));
|
||||
targetSurface->SetDeviceOffset(gfxPoint(-x, -y));
|
||||
DrawTo(targetSurface, dirtyRect);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user