2012-04-24 12:13:36 -07:00
|
|
|
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
|
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
|
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
|
|
|
|
package org.mozilla.gecko.gfx;
|
|
|
|
|
|
|
|
import org.mozilla.gecko.GeckoAppShell;
|
|
|
|
import org.mozilla.gecko.gfx.BufferedCairoImage;
|
|
|
|
import org.mozilla.gecko.gfx.CairoImage;
|
2012-04-26 10:45:31 -07:00
|
|
|
import org.mozilla.gecko.gfx.FloatSize;
|
2012-04-24 12:13:36 -07:00
|
|
|
import org.mozilla.gecko.gfx.IntSize;
|
|
|
|
import org.mozilla.gecko.gfx.SingleTileLayer;
|
|
|
|
import android.graphics.Bitmap;
|
|
|
|
import android.graphics.Canvas;
|
|
|
|
import android.graphics.Color;
|
|
|
|
import android.graphics.Paint;
|
|
|
|
import android.graphics.Rect;
|
|
|
|
import android.graphics.RectF;
|
|
|
|
import android.graphics.Region;
|
|
|
|
import android.graphics.RegionIterator;
|
|
|
|
import android.opengl.GLES20;
|
|
|
|
import android.util.Log;
|
|
|
|
import java.nio.ByteBuffer;
|
|
|
|
import java.nio.IntBuffer;
|
|
|
|
import java.nio.FloatBuffer;
|
|
|
|
|
|
|
|
public class ScreenshotLayer extends SingleTileLayer {
|
|
|
|
private static final int SCREENSHOT_SIZE_LIMIT = 1048576;
|
2012-06-27 07:52:11 -07:00
|
|
|
private static final int BYTES_FOR_16BPP = 2;
|
2012-04-24 12:13:36 -07:00
|
|
|
private ScreenshotImage mImage;
|
|
|
|
// Size of the image buffer
|
|
|
|
private IntSize mBufferSize;
|
|
|
|
// The size of the bitmap painted in the buffer
|
|
|
|
// (may be smaller than mBufferSize due to power of 2 padding)
|
|
|
|
private IntSize mImageSize;
|
2012-04-27 09:54:18 -07:00
|
|
|
// Whether we have an up-to-date image to draw
|
|
|
|
private boolean mHasImage;
|
2012-06-14 09:08:51 -07:00
|
|
|
private static String LOGTAG = "GeckoScreenshot";
|
2012-04-24 12:13:36 -07:00
|
|
|
|
|
|
|
public static int getMaxNumPixels() {
|
|
|
|
return SCREENSHOT_SIZE_LIMIT;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void reset() {
|
2012-04-27 09:54:18 -07:00
|
|
|
mHasImage = false;
|
2012-04-24 12:13:36 -07:00
|
|
|
}
|
|
|
|
|
2012-06-14 09:08:51 -07:00
|
|
|
void setBitmap(ByteBuffer data, int width, int height, Rect rect) {
|
|
|
|
mImageSize = new IntSize(width, height);
|
|
|
|
if (IntSize.isPowerOfTwo(width) && IntSize.isPowerOfTwo(height)) {
|
|
|
|
mBufferSize = mImageSize;
|
|
|
|
mHasImage = true;
|
|
|
|
mImage.setBitmap(data, width, height, CairoImage.FORMAT_RGB16_565, rect);
|
|
|
|
} else {
|
|
|
|
Bitmap b = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
|
|
|
|
b.copyPixelsFromBuffer(data);
|
|
|
|
setBitmap(b);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-04-24 12:13:36 -07:00
|
|
|
void setBitmap(Bitmap bitmap) {
|
|
|
|
mImageSize = new IntSize(bitmap.getWidth(), bitmap.getHeight());
|
|
|
|
int width = IntSize.nextPowerOfTwo(bitmap.getWidth());
|
|
|
|
int height = IntSize.nextPowerOfTwo(bitmap.getHeight());
|
|
|
|
mBufferSize = new IntSize(width, height);
|
|
|
|
mImage.setBitmap(bitmap, width, height, CairoImage.FORMAT_RGB16_565);
|
2012-04-27 09:54:18 -07:00
|
|
|
mHasImage = true;
|
2012-04-24 12:13:36 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
public void updateBitmap(Bitmap bitmap, float x, float y, float width, float height) {
|
|
|
|
mImage.updateBitmap(bitmap, x, y, width, height);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static ScreenshotLayer create() {
|
2012-04-27 09:54:18 -07:00
|
|
|
return ScreenshotLayer.create(new IntSize(4, 4));
|
2012-04-24 12:13:36 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
public static ScreenshotLayer create(IntSize size) {
|
|
|
|
Bitmap bitmap = Bitmap.createBitmap(size.width, size.height, Bitmap.Config.RGB_565);
|
|
|
|
ScreenshotLayer sl = create(bitmap);
|
|
|
|
sl.reset();
|
|
|
|
return sl;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static ScreenshotLayer create(Bitmap bitmap) {
|
|
|
|
IntSize size = new IntSize(bitmap.getWidth(), bitmap.getHeight());
|
|
|
|
// allocate a buffer that can hold our max screenshot size
|
2012-06-27 07:52:11 -07:00
|
|
|
ByteBuffer buffer = GeckoAppShell.allocateDirectBuffer(SCREENSHOT_SIZE_LIMIT * BYTES_FOR_16BPP);
|
2012-04-24 12:13:36 -07:00
|
|
|
// construct the screenshot layer
|
|
|
|
ScreenshotLayer sl = new ScreenshotLayer(new ScreenshotImage(buffer, size.width, size.height, CairoImage.FORMAT_RGB16_565), size);
|
|
|
|
// paint the passed in bitmap into the buffer
|
|
|
|
sl.setBitmap(bitmap);
|
|
|
|
return sl;
|
|
|
|
}
|
|
|
|
|
|
|
|
private ScreenshotLayer(ScreenshotImage image, IntSize size) {
|
2012-04-27 09:54:18 -07:00
|
|
|
super(image, TileLayer.PaintMode.NORMAL);
|
2012-04-24 12:13:36 -07:00
|
|
|
mBufferSize = size;
|
|
|
|
mImage = image;
|
|
|
|
}
|
|
|
|
|
2012-04-27 09:54:18 -07:00
|
|
|
@Override
|
|
|
|
public void draw(RenderContext context) {
|
|
|
|
if (mHasImage)
|
|
|
|
super.draw(context);
|
2012-04-24 12:13:36 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/** A Cairo image that simply saves a buffer of pixel data. */
|
|
|
|
static class ScreenshotImage extends CairoImage {
|
2012-04-27 09:54:18 -07:00
|
|
|
private ByteBuffer mBuffer;
|
2012-04-24 12:13:36 -07:00
|
|
|
private IntSize mSize;
|
|
|
|
private int mFormat;
|
|
|
|
|
|
|
|
/** Creates a buffered Cairo image from a byte buffer. */
|
|
|
|
public ScreenshotImage(ByteBuffer inBuffer, int inWidth, int inHeight, int inFormat) {
|
2012-05-10 06:46:53 -07:00
|
|
|
mBuffer = inBuffer;
|
|
|
|
mSize = new IntSize(inWidth, inHeight);
|
|
|
|
mFormat = inFormat;
|
2012-04-24 12:13:36 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected void finalize() throws Throwable {
|
|
|
|
try {
|
2012-05-10 06:46:53 -07:00
|
|
|
if (mBuffer != null) {
|
2012-04-24 12:13:36 -07:00
|
|
|
GeckoAppShell.freeDirectBuffer(mBuffer);
|
2012-05-10 06:46:53 -07:00
|
|
|
mBuffer = null;
|
|
|
|
}
|
2012-04-24 12:13:36 -07:00
|
|
|
} finally {
|
|
|
|
super.finalize();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-14 09:08:51 -07:00
|
|
|
void copyBuffer(ByteBuffer src, ByteBuffer dst, Rect rect, int stride) {
|
2012-06-27 07:52:11 -07:00
|
|
|
int start = (rect.top * stride) + (rect.left * BYTES_FOR_16BPP);
|
|
|
|
int end = ((rect.bottom - 1) * stride) + (rect.right * BYTES_FOR_16BPP);
|
|
|
|
// clamp stuff just to be safe
|
|
|
|
start = Math.max(0, Math.min(dst.limit(), Math.min(src.limit(), start)));
|
|
|
|
end = Math.max(start, Math.min(dst.limit(), Math.min(src.capacity(), end)));
|
2012-06-14 09:08:51 -07:00
|
|
|
dst.position(start);
|
|
|
|
src.position(start).limit(end);
|
2012-07-03 17:07:55 -07:00
|
|
|
dst.put(src);
|
2012-06-14 09:08:51 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
synchronized void setBitmap(ByteBuffer data, int width, int height, int format, Rect rect) {
|
|
|
|
mSize = new IntSize(width, height);
|
|
|
|
mFormat = format;
|
2012-06-27 07:52:11 -07:00
|
|
|
copyBuffer(data.asReadOnlyBuffer(), mBuffer.duplicate(), rect, width * BYTES_FOR_16BPP);
|
2012-06-14 09:08:51 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
synchronized void setBitmap(Bitmap bitmap, int width, int height, int format) {
|
2012-04-24 12:13:36 -07:00
|
|
|
Bitmap tmp;
|
|
|
|
mSize = new IntSize(width, height);
|
|
|
|
mFormat = format;
|
|
|
|
if (width == bitmap.getWidth() && height == bitmap.getHeight()) {
|
|
|
|
tmp = bitmap;
|
|
|
|
} else {
|
|
|
|
tmp = Bitmap.createBitmap(width, height, CairoUtils.cairoFormatTobitmapConfig(mFormat));
|
|
|
|
new Canvas(tmp).drawBitmap(bitmap, 0.0f, 0.0f, new Paint());
|
|
|
|
}
|
|
|
|
tmp.copyPixelsToBuffer(mBuffer.asIntBuffer());
|
|
|
|
}
|
|
|
|
|
|
|
|
public void updateBitmap(Bitmap bitmap, float x, float y, float width, float height) {
|
|
|
|
Bitmap tmp = Bitmap.createBitmap(mSize.width, mSize.height, CairoUtils.cairoFormatTobitmapConfig(mFormat));
|
|
|
|
tmp.copyPixelsFromBuffer(mBuffer.asIntBuffer());
|
|
|
|
Canvas c = new Canvas(tmp);
|
|
|
|
c.drawBitmap(bitmap, x, y, new Paint());
|
|
|
|
tmp.copyPixelsToBuffer(mBuffer.asIntBuffer());
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2012-06-14 09:08:51 -07:00
|
|
|
synchronized public ByteBuffer getBuffer() { return mBuffer; }
|
2012-04-24 12:13:36 -07:00
|
|
|
@Override
|
2012-06-14 09:08:51 -07:00
|
|
|
synchronized public IntSize getSize() { return mSize; }
|
2012-04-24 12:13:36 -07:00
|
|
|
@Override
|
2012-06-14 09:08:51 -07:00
|
|
|
synchronized public int getFormat() { return mFormat; }
|
2012-04-24 12:13:36 -07:00
|
|
|
}
|
|
|
|
}
|