зеркало из https://github.com/mozilla/pjs.git
Backout changeset 3e972d3efc11 (bug 708307) because it breaks Android tests; a=me
This commit is contained in:
Родитель
15c0041cbb
Коммит
1d5a7be0a9
|
@ -491,6 +491,15 @@ public class GeckoAppShell
|
||||||
/*
|
/*
|
||||||
* The Gecko-side API: API methods that Gecko calls
|
* The Gecko-side API: API methods that Gecko calls
|
||||||
*/
|
*/
|
||||||
|
public static void scheduleRedraw() {
|
||||||
|
// Redraw everything
|
||||||
|
Rect rect = new Rect(0, 0, LayerController.TILE_WIDTH, LayerController.TILE_HEIGHT);
|
||||||
|
GeckoEvent event = new GeckoEvent(GeckoEvent.DRAW, rect);
|
||||||
|
event.mNativeWindow = 0;
|
||||||
|
sendEventToGecko(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void notifyIME(int type, int state) {
|
public static void notifyIME(int type, int state) {
|
||||||
mInputConnection.notifyIME(type, state);
|
mInputConnection.notifyIME(type, state);
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,22 +46,21 @@ import java.nio.ByteBuffer;
|
||||||
/** A Cairo image that simply saves a buffer of pixel data. */
|
/** A Cairo image that simply saves a buffer of pixel data. */
|
||||||
public class BufferedCairoImage extends CairoImage {
|
public class BufferedCairoImage extends CairoImage {
|
||||||
private ByteBuffer mBuffer;
|
private ByteBuffer mBuffer;
|
||||||
private IntSize mSize;
|
private int mWidth, mHeight, mFormat;
|
||||||
private int mFormat;
|
|
||||||
private boolean mNeedToFreeBuffer = false;
|
private boolean mNeedToFreeBuffer = false;
|
||||||
|
|
||||||
/** Creates a buffered Cairo image from a byte buffer. */
|
/** Creates a buffered Cairo image from a byte buffer. */
|
||||||
public BufferedCairoImage(ByteBuffer inBuffer, int inWidth, int inHeight, int inFormat) {
|
public BufferedCairoImage(ByteBuffer inBuffer, int inWidth, int inHeight, int inFormat) {
|
||||||
mBuffer = inBuffer; mSize = new IntSize(inWidth, inHeight); mFormat = inFormat;
|
mBuffer = inBuffer; mWidth = inWidth; mHeight = inHeight; mFormat = inFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Creates a buffered Cairo image from an Android bitmap. */
|
/** Creates a buffered Cairo image from an Android bitmap. */
|
||||||
public BufferedCairoImage(Bitmap bitmap) {
|
public BufferedCairoImage(Bitmap bitmap) {
|
||||||
mFormat = CairoUtils.bitmapConfigToCairoFormat(bitmap.getConfig());
|
mFormat = CairoUtils.bitmapConfigToCairoFormat(bitmap.getConfig());
|
||||||
mSize = new IntSize(bitmap.getWidth(), bitmap.getHeight());
|
mWidth = bitmap.getWidth();
|
||||||
|
mHeight = bitmap.getHeight();
|
||||||
mNeedToFreeBuffer = true;
|
mNeedToFreeBuffer = true;
|
||||||
// XXX Why is this * 4? Shouldn't it depend on mFormat?
|
mBuffer = GeckoAppShell.allocateDirectBuffer(mWidth * mHeight * 4);
|
||||||
mBuffer = GeckoAppShell.allocateDirectBuffer(mSize.getArea() * 4);
|
|
||||||
bitmap.copyPixelsToBuffer(mBuffer.asIntBuffer());
|
bitmap.copyPixelsToBuffer(mBuffer.asIntBuffer());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,7 +78,9 @@ public class BufferedCairoImage extends CairoImage {
|
||||||
@Override
|
@Override
|
||||||
public ByteBuffer getBuffer() { return mBuffer; }
|
public ByteBuffer getBuffer() { return mBuffer; }
|
||||||
@Override
|
@Override
|
||||||
public IntSize getSize() { return mSize; }
|
public int getWidth() { return mWidth; }
|
||||||
|
@Override
|
||||||
|
public int getHeight() { return mHeight; }
|
||||||
@Override
|
@Override
|
||||||
public int getFormat() { return mFormat; }
|
public int getFormat() { return mFormat; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,8 @@ import java.nio.ByteBuffer;
|
||||||
public abstract class CairoImage {
|
public abstract class CairoImage {
|
||||||
public abstract ByteBuffer getBuffer();
|
public abstract ByteBuffer getBuffer();
|
||||||
|
|
||||||
public abstract IntSize getSize();
|
public abstract int getWidth();
|
||||||
|
public abstract int getHeight();
|
||||||
public abstract int getFormat();
|
public abstract int getFormat();
|
||||||
|
|
||||||
public static final int FORMAT_INVALID = -1;
|
public static final int FORMAT_INVALID = -1;
|
||||||
|
|
|
@ -72,9 +72,8 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL
|
||||||
private static final String LOGTAG = "GeckoSoftwareLayerClient";
|
private static final String LOGTAG = "GeckoSoftwareLayerClient";
|
||||||
|
|
||||||
private Context mContext;
|
private Context mContext;
|
||||||
private int mFormat;
|
private int mWidth, mHeight, mFormat;
|
||||||
private IntSize mScreenSize, mViewportSize;
|
private IntSize mScreenSize, mViewportSize;
|
||||||
private IntSize mBufferSize;
|
|
||||||
private ByteBuffer mBuffer;
|
private ByteBuffer mBuffer;
|
||||||
private final SingleTileLayer mTileLayer;
|
private final SingleTileLayer mTileLayer;
|
||||||
|
|
||||||
|
@ -98,15 +97,21 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL
|
||||||
public GeckoSoftwareLayerClient(Context context) {
|
public GeckoSoftwareLayerClient(Context context) {
|
||||||
mContext = context;
|
mContext = context;
|
||||||
|
|
||||||
mScreenSize = new IntSize(0, 0);
|
mWidth = LayerController.TILE_WIDTH;
|
||||||
mBufferSize = new IntSize(0, 0);
|
mHeight = LayerController.TILE_HEIGHT;
|
||||||
mFormat = CairoImage.FORMAT_RGB16_565;
|
mFormat = CairoImage.FORMAT_RGB16_565;
|
||||||
|
|
||||||
|
mScreenSize = new IntSize(1, 1);
|
||||||
|
|
||||||
|
mBuffer = GeckoAppShell.allocateDirectBuffer(mWidth * mHeight * 2);
|
||||||
|
|
||||||
mCairoImage = new CairoImage() {
|
mCairoImage = new CairoImage() {
|
||||||
@Override
|
@Override
|
||||||
public ByteBuffer getBuffer() { return mBuffer; }
|
public ByteBuffer getBuffer() { return mBuffer; }
|
||||||
@Override
|
@Override
|
||||||
public IntSize getSize() { return mBufferSize; }
|
public int getWidth() { return mWidth; }
|
||||||
|
@Override
|
||||||
|
public int getHeight() { return mHeight; }
|
||||||
@Override
|
@Override
|
||||||
public int getFormat() { return mFormat; }
|
public int getFormat() { return mFormat; }
|
||||||
};
|
};
|
||||||
|
@ -136,6 +141,7 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL
|
||||||
layerController.notifyPanZoomControllerOfGeometryChange(false);
|
layerController.notifyPanZoomControllerOfGeometryChange(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
geometryChanged();
|
||||||
GeckoAppShell.registerGeckoEventListener("Viewport:Update", this);
|
GeckoAppShell.registerGeckoEventListener("Viewport:Update", this);
|
||||||
GeckoAppShell.registerGeckoEventListener("Viewport:UpdateLater", this);
|
GeckoAppShell.registerGeckoEventListener("Viewport:UpdateLater", this);
|
||||||
}
|
}
|
||||||
|
@ -203,7 +209,7 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL
|
||||||
|
|
||||||
public Bitmap getBitmap() {
|
public Bitmap getBitmap() {
|
||||||
try {
|
try {
|
||||||
Bitmap b = Bitmap.createBitmap(mBufferSize.width, mBufferSize.height,
|
Bitmap b = Bitmap.createBitmap(mWidth, mHeight,
|
||||||
CairoUtils.cairoFormatTobitmapConfig(mFormat));
|
CairoUtils.cairoFormatTobitmapConfig(mFormat));
|
||||||
b.copyPixelsFromBuffer(mBuffer.asIntBuffer());
|
b.copyPixelsFromBuffer(mBuffer.asIntBuffer());
|
||||||
return b;
|
return b;
|
||||||
|
@ -235,28 +241,9 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL
|
||||||
if (metrics.widthPixels != mScreenSize.width ||
|
if (metrics.widthPixels != mScreenSize.width ||
|
||||||
metrics.heightPixels != mScreenSize.height) {
|
metrics.heightPixels != mScreenSize.height) {
|
||||||
mScreenSize = new IntSize(metrics.widthPixels, metrics.heightPixels);
|
mScreenSize = new IntSize(metrics.widthPixels, metrics.heightPixels);
|
||||||
int maxSize = getLayerController().getView().getMaxTextureSize();
|
|
||||||
|
|
||||||
// XXX Introduce tiling to solve this?
|
|
||||||
if (mScreenSize.width > maxSize || mScreenSize.height > maxSize)
|
|
||||||
throw new RuntimeException("Screen size of " + mScreenSize + " larger than maximum texture size of " + maxSize);
|
|
||||||
|
|
||||||
// Round to next power of two until we use NPOT texture support
|
|
||||||
mBufferSize = new IntSize(Math.min(maxSize, IntSize.nextPowerOfTwo(mScreenSize.width + LayerController.MIN_BUFFER.width)),
|
|
||||||
Math.min(maxSize, IntSize.nextPowerOfTwo(mScreenSize.height + LayerController.MIN_BUFFER.height)));
|
|
||||||
|
|
||||||
// Free the old buffer first, if it exists
|
|
||||||
if (mBuffer != null) {
|
|
||||||
GeckoAppShell.freeDirectBuffer(mBuffer);
|
|
||||||
mBuffer = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// * 2 because it's a 16-bit buffer (so 2 bytes per pixel).
|
|
||||||
mBuffer = GeckoAppShell.allocateDirectBuffer(mBufferSize.getArea() * 2);
|
|
||||||
|
|
||||||
Log.i(LOGTAG, "Screen-size changed to " + mScreenSize);
|
Log.i(LOGTAG, "Screen-size changed to " + mScreenSize);
|
||||||
GeckoEvent event = new GeckoEvent(GeckoEvent.SIZE_CHANGED,
|
GeckoEvent event = new GeckoEvent(GeckoEvent.SIZE_CHANGED,
|
||||||
mBufferSize.width, mBufferSize.height,
|
LayerController.TILE_WIDTH, LayerController.TILE_HEIGHT,
|
||||||
metrics.widthPixels, metrics.heightPixels);
|
metrics.widthPixels, metrics.heightPixels);
|
||||||
GeckoAppShell.sendEventToGecko(event);
|
GeckoAppShell.sendEventToGecko(event);
|
||||||
}
|
}
|
||||||
|
@ -302,7 +289,7 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL
|
||||||
ViewportMetrics viewportMetrics =
|
ViewportMetrics viewportMetrics =
|
||||||
new ViewportMetrics(getLayerController().getViewportMetrics());
|
new ViewportMetrics(getLayerController().getViewportMetrics());
|
||||||
|
|
||||||
PointF viewportOffset = viewportMetrics.getOptimumViewportOffset(mBufferSize);
|
PointF viewportOffset = viewportMetrics.getOptimumViewportOffset();
|
||||||
viewportMetrics.setViewportOffset(viewportOffset);
|
viewportMetrics.setViewportOffset(viewportOffset);
|
||||||
viewportMetrics.setViewport(viewportMetrics.getClampedViewport());
|
viewportMetrics.setViewport(viewportMetrics.getClampedViewport());
|
||||||
|
|
||||||
|
|
|
@ -62,18 +62,10 @@ public class IntSize {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getArea() {
|
|
||||||
return width * height;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean equals(IntSize size) {
|
public boolean equals(IntSize size) {
|
||||||
return ((size.width == width) && (size.height == height));
|
return ((size.width == width) && (size.height == height));
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isPositive() {
|
|
||||||
return (width > 0 && height > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() { return "(" + width + "," + height + ")"; }
|
public String toString() { return "(" + width + "," + height + ")"; }
|
||||||
|
|
||||||
|
@ -81,23 +73,5 @@ public class IntSize {
|
||||||
return new IntSize((int)Math.round(width * factor),
|
return new IntSize((int)Math.round(width * factor),
|
||||||
(int)Math.round(height * factor));
|
(int)Math.round(height * factor));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns the power of two that is greater than or equal to value */
|
|
||||||
public static int nextPowerOfTwo(int value) {
|
|
||||||
// code taken from http://acius2.blogspot.com/2007/11/calculating-next-power-of-2.html
|
|
||||||
if (0 == value--) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
value = (value >> 1) | value;
|
|
||||||
value = (value >> 2) | value;
|
|
||||||
value = (value >> 4) | value;
|
|
||||||
value = (value >> 8) | value;
|
|
||||||
value = (value >> 16) | value;
|
|
||||||
return value + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IntSize nextPowerOfTwo() {
|
|
||||||
return new IntSize(nextPowerOfTwo(width), nextPowerOfTwo(height));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -80,9 +80,6 @@ public abstract class Layer {
|
||||||
/** Subclasses override this function to draw the layer. */
|
/** Subclasses override this function to draw the layer. */
|
||||||
public abstract void draw(RenderContext context);
|
public abstract void draw(RenderContext context);
|
||||||
|
|
||||||
/** Subclasses override this function to provide access to the size of the layer. */
|
|
||||||
public abstract IntSize getSize();
|
|
||||||
|
|
||||||
/** Given the intrinsic size of the layer, returns the pixel boundaries of the layer rect. */
|
/** Given the intrinsic size of the layer, returns the pixel boundaries of the layer rect. */
|
||||||
protected RectF getBounds(RenderContext context, FloatSize size) {
|
protected RectF getBounds(RenderContext context, FloatSize size) {
|
||||||
float scaleFactor = context.zoomFactor / mResolution;
|
float scaleFactor = context.zoomFactor / mResolution;
|
||||||
|
@ -171,6 +168,20 @@ public abstract class Layer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Returns the power of two that is greater than or equal to value */
|
||||||
|
protected static int nextPowerOfTwo(int value) {
|
||||||
|
// code taken from http://acius2.blogspot.com/2007/11/calculating-next-power-of-2.html
|
||||||
|
if (0 == value--) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
value = (value >> 1) | value;
|
||||||
|
value = (value >> 2) | value;
|
||||||
|
value = (value >> 4) | value;
|
||||||
|
value = (value >> 8) | value;
|
||||||
|
value = (value >> 16) | value;
|
||||||
|
return value + 1;
|
||||||
|
}
|
||||||
|
|
||||||
public static class RenderContext {
|
public static class RenderContext {
|
||||||
public final RectF viewport;
|
public final RectF viewport;
|
||||||
public final FloatSize pageSize;
|
public final FloatSize pageSize;
|
||||||
|
|
|
@ -85,11 +85,9 @@ public class LayerController {
|
||||||
|
|
||||||
private boolean mForceRedraw;
|
private boolean mForceRedraw;
|
||||||
|
|
||||||
/* The extra area on the sides of the page that we want to buffer to help with
|
/* NB: These must be powers of two due to the OpenGL ES 1.x restriction on NPOT textures. */
|
||||||
* smooth, asynchronous scrolling. Depending on a device's support for NPOT
|
public static final int TILE_WIDTH = 1024;
|
||||||
* textures, this may be rounded up to the nearest power of two.
|
public static final int TILE_HEIGHT = 2048;
|
||||||
*/
|
|
||||||
public static final IntSize MIN_BUFFER = new IntSize(512, 1024);
|
|
||||||
|
|
||||||
/* If the visible rect is within the danger zone (measured in pixels from each edge of a tile),
|
/* If the visible rect is within the danger zone (measured in pixels from each edge of a tile),
|
||||||
* we start aggressively redrawing to minimize checkerboarding. */
|
* we start aggressively redrawing to minimize checkerboarding. */
|
||||||
|
@ -295,12 +293,8 @@ public class LayerController {
|
||||||
}
|
}
|
||||||
|
|
||||||
private RectF getTileRect() {
|
private RectF getTileRect() {
|
||||||
if (mRootLayer == null)
|
|
||||||
return new RectF();
|
|
||||||
|
|
||||||
float x = mRootLayer.getOrigin().x, y = mRootLayer.getOrigin().y;
|
float x = mRootLayer.getOrigin().x, y = mRootLayer.getOrigin().y;
|
||||||
IntSize layerSize = mRootLayer.getSize();
|
return new RectF(x, y, x + TILE_WIDTH, y + TILE_HEIGHT);
|
||||||
return new RectF(x, y, x + layerSize.width, y + layerSize.height);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public RectF restrictToPageSize(RectF aRect) {
|
public RectF restrictToPageSize(RectF aRect) {
|
||||||
|
|
|
@ -90,7 +90,6 @@ public class LayerRenderer implements GLSurfaceView.Renderer {
|
||||||
private final ScrollbarLayer mVertScrollLayer;
|
private final ScrollbarLayer mVertScrollLayer;
|
||||||
private final FadeRunnable mFadeRunnable;
|
private final FadeRunnable mFadeRunnable;
|
||||||
private RenderContext mLastPageContext;
|
private RenderContext mLastPageContext;
|
||||||
private int mMaxTextureSize;
|
|
||||||
|
|
||||||
// Dropped frames display
|
// Dropped frames display
|
||||||
private int[] mFrameTimings;
|
private int[] mFrameTimings;
|
||||||
|
@ -123,17 +122,12 @@ public class LayerRenderer implements GLSurfaceView.Renderer {
|
||||||
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
|
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
|
||||||
checkFrameRateMonitorEnabled();
|
checkFrameRateMonitorEnabled();
|
||||||
|
|
||||||
|
gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||||
|
gl.glClearDepthf(1.0f); /* FIXME: Is this needed? */
|
||||||
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
|
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
|
||||||
|
gl.glShadeModel(GL10.GL_SMOOTH); /* FIXME: Is this needed? */
|
||||||
gl.glDisable(GL10.GL_DITHER);
|
gl.glDisable(GL10.GL_DITHER);
|
||||||
gl.glEnable(GL10.GL_TEXTURE_2D);
|
gl.glEnable(GL10.GL_TEXTURE_2D);
|
||||||
|
|
||||||
int maxTextureSizeResult[] = new int[1];
|
|
||||||
gl.glGetIntegerv(GL10.GL_MAX_TEXTURE_SIZE, maxTextureSizeResult, 0);
|
|
||||||
mMaxTextureSize = maxTextureSizeResult[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getMaxTextureSize() {
|
|
||||||
return mMaxTextureSize;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -167,9 +167,5 @@ public class LayerView extends GLSurfaceView {
|
||||||
return System.nanoTime() - mRenderTime;
|
return System.nanoTime() - mRenderTime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getMaxTextureSize() {
|
|
||||||
return mRenderer.getMaxTextureSize();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -82,8 +82,7 @@ public class ScrollbarLayer extends TileLayer {
|
||||||
mVertical = vertical;
|
mVertical = vertical;
|
||||||
mBuffer = buffer;
|
mBuffer = buffer;
|
||||||
|
|
||||||
IntSize size = image.getSize();
|
mBitmap = Bitmap.createBitmap(image.getWidth(), image.getHeight(), Bitmap.Config.ARGB_8888);
|
||||||
mBitmap = Bitmap.createBitmap(size.width, size.height, Bitmap.Config.ARGB_8888);
|
|
||||||
mCanvas = new Canvas(mBitmap);
|
mCanvas = new Canvas(mBitmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,7 +100,7 @@ public class ScrollbarLayer extends TileLayer {
|
||||||
public static ScrollbarLayer create(boolean vertical) {
|
public static ScrollbarLayer create(boolean vertical) {
|
||||||
// just create an empty image for now, it will get drawn
|
// just create an empty image for now, it will get drawn
|
||||||
// on demand anyway
|
// on demand anyway
|
||||||
int imageSize = IntSize.nextPowerOfTwo(BAR_SIZE);
|
int imageSize = nextPowerOfTwo(BAR_SIZE);
|
||||||
ByteBuffer buffer = GeckoAppShell.allocateDirectBuffer(imageSize * imageSize * 4);
|
ByteBuffer buffer = GeckoAppShell.allocateDirectBuffer(imageSize * imageSize * 4);
|
||||||
CairoImage image = new BufferedCairoImage(buffer, imageSize, imageSize, CairoImage.FORMAT_ARGB32);
|
CairoImage image = new BufferedCairoImage(buffer, imageSize, imageSize, CairoImage.FORMAT_ARGB32);
|
||||||
return new ScrollbarLayer(image, vertical, buffer);
|
return new ScrollbarLayer(image, vertical, buffer);
|
||||||
|
|
|
@ -39,7 +39,6 @@ package org.mozilla.gecko.gfx;
|
||||||
|
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.graphics.RectF;
|
import android.graphics.RectF;
|
||||||
import android.opengl.GLES20;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import javax.microedition.khronos.opengles.GL10;
|
import javax.microedition.khronos.opengles.GL10;
|
||||||
import javax.microedition.khronos.opengles.GL11Ext;
|
import javax.microedition.khronos.opengles.GL11Ext;
|
||||||
|
@ -59,18 +58,27 @@ public abstract class TileLayer extends Layer {
|
||||||
private final ArrayList<Rect> mDirtyRects;
|
private final ArrayList<Rect> mDirtyRects;
|
||||||
private final CairoImage mImage;
|
private final CairoImage mImage;
|
||||||
private final boolean mRepeat;
|
private final boolean mRepeat;
|
||||||
private IntSize mSize;
|
private final IntSize mSize;
|
||||||
private int[] mTextureIDs;
|
private int[] mTextureIDs;
|
||||||
|
|
||||||
public TileLayer(boolean repeat, CairoImage image) {
|
public TileLayer(boolean repeat, CairoImage image) {
|
||||||
mRepeat = repeat;
|
mRepeat = repeat;
|
||||||
mImage = image;
|
mImage = image;
|
||||||
mSize = new IntSize(0, 0);
|
mSize = new IntSize(image.getWidth(), image.getHeight());
|
||||||
mDirtyRects = new ArrayList<Rect>();
|
mDirtyRects = new ArrayList<Rect>();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Assert that the image has a power-of-two size. OpenGL ES < 2.0 doesn't support NPOT
|
||||||
|
* textures and OpenGL ES doesn't seem to let us efficiently slice up a NPOT bitmap.
|
||||||
|
*/
|
||||||
|
int width = mImage.getWidth(), height = mImage.getHeight();
|
||||||
|
if ((width & (width - 1)) != 0 || (height & (height - 1)) != 0) {
|
||||||
|
throw new RuntimeException("TileLayer: NPOT images are unsupported (dimensions are " +
|
||||||
|
width + "x" + height + ")");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public IntSize getSize() { return mSize; }
|
||||||
public IntSize getSize() { return mImage.getSize(); }
|
|
||||||
|
|
||||||
protected boolean repeats() { return mRepeat; }
|
protected boolean repeats() { return mRepeat; }
|
||||||
protected int getTextureID() { return mTextureIDs[0]; }
|
protected int getTextureID() { return mTextureIDs[0]; }
|
||||||
|
@ -93,49 +101,13 @@ public abstract class TileLayer extends Layer {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void invalidate() {
|
public void invalidate() {
|
||||||
IntSize bufferSize = mImage.getSize();
|
invalidate(new Rect(0, 0, mSize.width, mSize.height));
|
||||||
invalidate(new Rect(0, 0, bufferSize.width, bufferSize.height));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void validateTexture() {
|
|
||||||
/* Calculate the ideal texture size. This must be a power of two if
|
|
||||||
* the texture is repeated or OpenGL ES 2.0 isn't supported, as
|
|
||||||
* OpenGL ES 2.0 is required for NPOT texture support (without
|
|
||||||
* extensions), but doesn't support repeating NPOT textures.
|
|
||||||
*
|
|
||||||
* XXX Currently, we don't pick a GLES 2.0 context, so always round.
|
|
||||||
*/
|
|
||||||
IntSize bufferSize = mImage.getSize();
|
|
||||||
IntSize textureSize = bufferSize;
|
|
||||||
|
|
||||||
textureSize = bufferSize.nextPowerOfTwo();
|
|
||||||
|
|
||||||
if (!textureSize.equals(mSize)) {
|
|
||||||
mSize = textureSize;
|
|
||||||
|
|
||||||
// Delete the old texture
|
|
||||||
if (mTextureIDs != null) {
|
|
||||||
TextureReaper.get().add(mTextureIDs);
|
|
||||||
mTextureIDs = null;
|
|
||||||
|
|
||||||
// XXX This won't be freed until the next frame is drawn, so we
|
|
||||||
// temporarily have a larger-than-necessary memory requirement.
|
|
||||||
// Is this what we want?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void performUpdates(GL10 gl) {
|
protected void performUpdates(GL10 gl) {
|
||||||
super.performUpdates(gl);
|
super.performUpdates(gl);
|
||||||
|
|
||||||
// Reallocate the texture if the size has changed
|
|
||||||
validateTexture();
|
|
||||||
|
|
||||||
// Don't do any work if the image has an invalid size.
|
|
||||||
if (!mImage.getSize().isPositive())
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (mTextureIDs == null) {
|
if (mTextureIDs == null) {
|
||||||
uploadFullTexture(gl);
|
uploadFullTexture(gl);
|
||||||
} else {
|
} else {
|
||||||
|
@ -147,58 +119,43 @@ public abstract class TileLayer extends Layer {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void uploadFullTexture(GL10 gl) {
|
private void uploadFullTexture(GL10 gl) {
|
||||||
IntSize bufferSize = mImage.getSize();
|
|
||||||
uploadDirtyRect(gl, new Rect(0, 0, bufferSize.width, bufferSize.height));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void uploadDirtyRect(GL10 gl, Rect dirtyRect) {
|
|
||||||
boolean newlyCreated = false;
|
|
||||||
|
|
||||||
if (mTextureIDs == null) {
|
|
||||||
mTextureIDs = new int[1];
|
mTextureIDs = new int[1];
|
||||||
gl.glGenTextures(mTextureIDs.length, mTextureIDs, 0);
|
gl.glGenTextures(mTextureIDs.length, mTextureIDs, 0);
|
||||||
newlyCreated = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
IntSize bufferSize = mImage.getSize();
|
|
||||||
Rect bufferRect = new Rect(0, 0, bufferSize.width, bufferSize.height);
|
|
||||||
|
|
||||||
int cairoFormat = mImage.getFormat();
|
int cairoFormat = mImage.getFormat();
|
||||||
CairoGLInfo glInfo = new CairoGLInfo(cairoFormat);
|
CairoGLInfo glInfo = new CairoGLInfo(cairoFormat);
|
||||||
|
|
||||||
bindAndSetGLParameters(gl);
|
bindAndSetGLParameters(gl);
|
||||||
|
|
||||||
if (newlyCreated || dirtyRect.equals(bufferRect)) {
|
|
||||||
if (mSize.equals(bufferSize)) {
|
|
||||||
gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, glInfo.internalFormat, mSize.width, mSize.height,
|
gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, glInfo.internalFormat, mSize.width, mSize.height,
|
||||||
0, glInfo.format, glInfo.type, mImage.getBuffer());
|
0, glInfo.format, glInfo.type, mImage.getBuffer());
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, glInfo.internalFormat, mSize.width, mSize.height,
|
|
||||||
0, glInfo.format, glInfo.type, null);
|
|
||||||
gl.glTexSubImage2D(gl.GL_TEXTURE_2D, 0, 0, 0, bufferSize.width, bufferSize.height,
|
|
||||||
glInfo.format, glInfo.type, mImage.getBuffer());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void uploadDirtyRect(GL10 gl, Rect dirtyRect) {
|
||||||
|
if (mTextureIDs == null)
|
||||||
|
throw new RuntimeException("uploadDirtyRect() called with null texture ID!");
|
||||||
|
|
||||||
|
int width = mSize.width;
|
||||||
|
int cairoFormat = mImage.getFormat();
|
||||||
|
CairoGLInfo glInfo = new CairoGLInfo(cairoFormat);
|
||||||
|
|
||||||
|
bindAndSetGLParameters(gl);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Upload the changed rect. We have to widen to the full width of the texture
|
* 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,
|
* because we can't count on the device having support for GL_EXT_unpack_subimage,
|
||||||
* and going line-by-line is too slow.
|
* and going line-by-line is too slow.
|
||||||
*
|
|
||||||
* XXX We should still use GL_EXT_unpack_subimage when available.
|
|
||||||
*/
|
*/
|
||||||
Buffer viewBuffer = mImage.getBuffer().slice();
|
Buffer viewBuffer = mImage.getBuffer().slice();
|
||||||
int bpp = CairoUtils.bitsPerPixelForCairoFormat(cairoFormat) / 8;
|
int bpp = CairoUtils.bitsPerPixelForCairoFormat(cairoFormat) / 8;
|
||||||
int position = dirtyRect.top * bufferSize.width * bpp;
|
int position = dirtyRect.top * width * bpp;
|
||||||
if (position > viewBuffer.limit()) {
|
if (position > viewBuffer.limit()) {
|
||||||
Log.e(LOGTAG, "### Position outside tile! " + dirtyRect.top);
|
Log.e(LOGTAG, "### Position outside tile! " + dirtyRect.top);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
viewBuffer.position(position);
|
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, width, dirtyRect.height(),
|
||||||
glInfo.format, glInfo.type, viewBuffer);
|
glInfo.format, glInfo.type, viewBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,6 @@ import android.graphics.Rect;
|
||||||
import android.graphics.RectF;
|
import android.graphics.RectF;
|
||||||
import org.mozilla.gecko.FloatUtils;
|
import org.mozilla.gecko.FloatUtils;
|
||||||
import org.mozilla.gecko.gfx.FloatSize;
|
import org.mozilla.gecko.gfx.FloatSize;
|
||||||
import org.mozilla.gecko.gfx.IntSize;
|
|
||||||
import org.mozilla.gecko.gfx.LayerController;
|
import org.mozilla.gecko.gfx.LayerController;
|
||||||
import org.mozilla.gecko.gfx.RectUtils;
|
import org.mozilla.gecko.gfx.RectUtils;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
|
@ -65,7 +64,8 @@ public class ViewportMetrics {
|
||||||
private float mZoomFactor;
|
private float mZoomFactor;
|
||||||
|
|
||||||
public ViewportMetrics() {
|
public ViewportMetrics() {
|
||||||
mPageSize = new FloatSize(1, 1);
|
mPageSize = new FloatSize(LayerController.TILE_WIDTH,
|
||||||
|
LayerController.TILE_HEIGHT);
|
||||||
mViewportRect = new RectF(0, 0, 1, 1);
|
mViewportRect = new RectF(0, 0, 1, 1);
|
||||||
mViewportOffset = new PointF(0, 0);
|
mViewportOffset = new PointF(0, 0);
|
||||||
mZoomFactor = 1.0f;
|
mZoomFactor = 1.0f;
|
||||||
|
@ -96,13 +96,13 @@ public class ViewportMetrics {
|
||||||
mZoomFactor = zoom;
|
mZoomFactor = zoom;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PointF getOptimumViewportOffset(IntSize displayportSize) {
|
public PointF getOptimumViewportOffset() {
|
||||||
// XXX We currently always position the viewport in the centre of the
|
// XXX We currently always position the viewport in the centre of the
|
||||||
// displayport, but we might want to optimise this during panning
|
// displayport, but we might want to optimise this during panning
|
||||||
// to minimise checkerboarding.
|
// to minimise checkerboarding.
|
||||||
Point optimumOffset =
|
Point optimumOffset =
|
||||||
new Point((int)Math.round((displayportSize.width - mViewportRect.width()) / 2),
|
new Point((int)Math.round((LayerController.TILE_WIDTH - mViewportRect.width()) / 2),
|
||||||
(int)Math.round((displayportSize.height - mViewportRect.height()) / 2));
|
(int)Math.round((LayerController.TILE_HEIGHT - mViewportRect.height()) / 2));
|
||||||
|
|
||||||
/* XXX Until bug #524925 is fixed, changing the viewport origin will
|
/* XXX Until bug #524925 is fixed, changing the viewport origin will
|
||||||
* probably cause things to be slower than just having a smaller usable
|
* probably cause things to be slower than just having a smaller usable
|
||||||
|
|
|
@ -79,6 +79,10 @@ using mozilla::unused;
|
||||||
|
|
||||||
#include "nsStringGlue.h"
|
#include "nsStringGlue.h"
|
||||||
|
|
||||||
|
// NB: Keep these in sync with LayerController.java in mobile/android/base and embedding/android/.
|
||||||
|
#define TILE_WIDTH 1024
|
||||||
|
#define TILE_HEIGHT 2048
|
||||||
|
|
||||||
using namespace mozilla;
|
using namespace mozilla;
|
||||||
using namespace mozilla::widget;
|
using namespace mozilla::widget;
|
||||||
|
|
||||||
|
@ -306,7 +310,7 @@ nsWindow::ConfigureChildren(const nsTArray<nsIWidget::Configuration>& config)
|
||||||
void
|
void
|
||||||
nsWindow::RedrawAll()
|
nsWindow::RedrawAll()
|
||||||
{
|
{
|
||||||
nsIntRect entireRect(0, 0, gAndroidBounds.width, gAndroidBounds.height);
|
nsIntRect entireRect(0, 0, TILE_WIDTH, TILE_HEIGHT);
|
||||||
AndroidGeckoEvent *event = new AndroidGeckoEvent(AndroidGeckoEvent::DRAW, entireRect);
|
AndroidGeckoEvent *event = new AndroidGeckoEvent(AndroidGeckoEvent::DRAW, entireRect);
|
||||||
nsAppShell::gAppShell->PostEvent(event);
|
nsAppShell::gAppShell->PostEvent(event);
|
||||||
}
|
}
|
||||||
|
@ -1014,7 +1018,7 @@ nsWindow::DrawTo(gfxASurface *targetSurface, const nsIntRect &invalidRect)
|
||||||
if (coveringChildIndex == -1) {
|
if (coveringChildIndex == -1) {
|
||||||
nsPaintEvent event(true, NS_PAINT, this);
|
nsPaintEvent event(true, NS_PAINT, this);
|
||||||
|
|
||||||
nsIntRect tileRect(0, 0, gAndroidBounds.width, gAndroidBounds.height);
|
nsIntRect tileRect(0, 0, TILE_WIDTH, TILE_HEIGHT);
|
||||||
event.region = boundsRect.Intersect(invalidRect).Intersect(tileRect);
|
event.region = boundsRect.Intersect(invalidRect).Intersect(tileRect);
|
||||||
|
|
||||||
switch (GetLayerManager(nsnull)->GetBackendType()) {
|
switch (GetLayerManager(nsnull)->GetBackendType()) {
|
||||||
|
@ -1108,7 +1112,7 @@ nsWindow::OnDraw(AndroidGeckoEvent *ae)
|
||||||
|
|
||||||
unsigned char *bits = client.LockBufferBits();
|
unsigned char *bits = client.LockBufferBits();
|
||||||
nsRefPtr<gfxImageSurface> targetSurface =
|
nsRefPtr<gfxImageSurface> targetSurface =
|
||||||
new gfxImageSurface(bits, gfxIntSize(gAndroidBounds.width, gAndroidBounds.height), gAndroidBounds.width * 2,
|
new gfxImageSurface(bits, gfxIntSize(TILE_WIDTH, TILE_HEIGHT), TILE_WIDTH * 2,
|
||||||
gfxASurface::ImageFormatRGB16_565);
|
gfxASurface::ImageFormatRGB16_565);
|
||||||
if (targetSurface->CairoStatus()) {
|
if (targetSurface->CairoStatus()) {
|
||||||
ALOG("### Failed to create a valid surface from the bitmap");
|
ALOG("### Failed to create a valid surface from the bitmap");
|
||||||
|
|
Загрузка…
Ссылка в новой задаче