Bug 803299 - Enable 32-bit colour on Android. r=kats

This commit is contained in:
Chris Lord 2013-07-04 14:53:25 +01:00
parent 508e8b2f4d
commit 4dcb88c93c
9 changed files with 122 additions and 17 deletions

View File

@ -37,6 +37,7 @@ import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ImageFormat;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.SurfaceTexture;
@ -134,6 +135,7 @@ public class GeckoAppShell
static private final boolean LOGGING = false;
static private int sDensityDpi = 0;
static private int sScreenDepth = 0;
private static final EventDispatcher sEventDispatcher = new EventDispatcher();
@ -1320,6 +1322,27 @@ public class GeckoAppShell
return sDensityDpi;
}
/**
* Returns the colour depth of the default screen. This will either be
* 24 or 16.
*/
public static int getScreenDepth() {
if (sScreenDepth == 0 && getGeckoInterface() != null) {
switch (getGeckoInterface().getActivity().getWindowManager().getDefaultDisplay().getPixelFormat()) {
case PixelFormat.RGBA_8888 :
case PixelFormat.RGBX_8888 :
case PixelFormat.RGB_888 :
sScreenDepth = 24;
break;
default:
sScreenDepth = 16;
break;
}
}
return sScreenDepth;
}
public static void setFullScreen(boolean fullscreen) {
if (getGeckoInterface() != null)
getGeckoInterface().setFullScreen(fullscreen);

View File

@ -182,7 +182,9 @@ public class Tab {
}
if (mThumbnailBitmap == null) {
mThumbnailBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
Bitmap.Config config = (GeckoAppShell.getScreenDepth() == 24) ?
Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
mThumbnailBitmap = Bitmap.createBitmap(width, height, config);
}
return mThumbnailBitmap;

View File

@ -105,7 +105,8 @@ public final class ThumbnailHelper {
mWidth &= ~0x1; // Ensure the width is always an even number (bug 776906)
mHeight = Math.round(mWidth * THUMBNAIL_ASPECT_RATIO);
int capacity = mWidth * mHeight * 2; // Multiply by 2 for 16bpp
int pixelSize = (GeckoAppShell.getScreenDepth() == 24) ? 4 : 2;
int capacity = mWidth * mHeight * pixelSize;
if (mBuffer == null || mBuffer.capacity() != capacity) {
if (mBuffer != null) {
mBuffer = DirectBufferAllocator.free(mBuffer);
@ -182,7 +183,23 @@ public final class ThumbnailHelper {
private void processThumbnailData(Tab tab, ByteBuffer data) {
Bitmap b = tab.getThumbnailBitmap(mWidth, mHeight);
data.position(0);
b.copyPixelsFromBuffer(data);
if (b.getConfig() == Bitmap.Config.RGB_565) {
b.copyPixelsFromBuffer(data);
} else {
// Unfortunately, Gecko's 32-bit format is BGRA and Android's is
// ARGB, so we need to manually swizzle.
for (int y = 0; y < mHeight; y++) {
for (int x = 0; x < mWidth; x++) {
int index = (y * mWidth + x) * 4;
int bgra = data.getInt(index);
int argb = ((bgra << 24) & 0xFF000000)
| ((bgra << 8) & 0x00FF0000)
| ((bgra >> 8) & 0x0000FF00)
| ((bgra >> 24) & 0x000000FF);
b.setPixel(x, y, argb);
}
}
}
setTabThumbnail(tab, b, null);
}

View File

@ -49,7 +49,7 @@ public class GLController {
private static final int LOCAL_EGL_OPENGL_ES2_BIT = 4;
private static final int[] CONFIG_SPEC = {
private static final int[] CONFIG_SPEC_16BPP = {
EGL10.EGL_RED_SIZE, 5,
EGL10.EGL_GREEN_SIZE, 6,
EGL10.EGL_BLUE_SIZE, 5,
@ -58,6 +58,15 @@ public class GLController {
EGL10.EGL_NONE
};
private static final int[] CONFIG_SPEC_24BPP = {
EGL10.EGL_RED_SIZE, 8,
EGL10.EGL_GREEN_SIZE, 8,
EGL10.EGL_BLUE_SIZE, 8,
EGL10.EGL_SURFACE_TYPE, EGL10.EGL_WINDOW_BIT,
EGL10.EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT,
EGL10.EGL_NONE
};
private GLController() {
// Here we start the GfxInfo thread, which will query OpenGL
// system information for Gecko. This must be done early enough that the data will be
@ -202,26 +211,41 @@ public class GLController {
}
private EGLConfig chooseConfig() {
int[] desiredConfig;
int rSize, gSize, bSize;
int[] numConfigs = new int[1];
if (!mEGL.eglChooseConfig(mEGLDisplay, CONFIG_SPEC, null, 0, numConfigs) ||
switch (GeckoAppShell.getScreenDepth()) {
case 24:
desiredConfig = CONFIG_SPEC_24BPP;
rSize = gSize = bSize = 8;
break;
case 16:
default:
desiredConfig = CONFIG_SPEC_16BPP;
rSize = 5; gSize = 6; bSize = 5;
break;
}
if (!mEGL.eglChooseConfig(mEGLDisplay, desiredConfig, null, 0, numConfigs) ||
numConfigs[0] <= 0) {
throw new GLControllerException("No available EGL configurations " +
getEGLError());
}
EGLConfig[] configs = new EGLConfig[numConfigs[0]];
if (!mEGL.eglChooseConfig(mEGLDisplay, CONFIG_SPEC, configs, numConfigs[0], numConfigs)) {
if (!mEGL.eglChooseConfig(mEGLDisplay, desiredConfig, configs, numConfigs[0], numConfigs)) {
throw new GLControllerException("No EGL configuration for that specification " +
getEGLError());
}
// Select the first 565 RGB configuration.
// Select the first configuration that matches the screen depth.
int[] red = new int[1], green = new int[1], blue = new int[1];
for (EGLConfig config : configs) {
mEGL.eglGetConfigAttrib(mEGLDisplay, config, EGL10.EGL_RED_SIZE, red);
mEGL.eglGetConfigAttrib(mEGLDisplay, config, EGL10.EGL_GREEN_SIZE, green);
mEGL.eglGetConfigAttrib(mEGLDisplay, config, EGL10.EGL_BLUE_SIZE, blue);
if (red[0] == 5 && green[0] == 6 && blue[0] == 5) {
if (red[0] == rSize && green[0] == gSize && blue[0] == bSize) {
return config;
}
}

View File

@ -316,7 +316,12 @@ public class TopSitesView extends GridView {
if (b == null)
continue;
Bitmap thumbnail = BitmapUtils.decodeByteArray(b);
Bitmap thumbnail = null;
try {
thumbnail = BitmapUtils.decodeByteArray(b);
} catch (IllegalArgumentException e) {
Log.e(LOGTAG, "Error decoding thumbnail", e);
}
if (thumbnail == null)
continue;

View File

@ -131,6 +131,7 @@ AndroidBridge::Init(JNIEnv *jEnv,
jAlertsProgressListener_OnProgress = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "alertsProgressListener_OnProgress", "(Ljava/lang/String;JJLjava/lang/String;)V");
jCloseNotification = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "closeNotification", "(Ljava/lang/String;)V");
jGetDpi = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getDpi", "()I");
jGetScreenDepth = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getScreenDepth", "()I");
jSetFullScreen = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "setFullScreen", "(Z)V");
jShowInputMethodPicker = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "showInputMethodPicker", "()V");
jNotifyDefaultPrevented = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "notifyDefaultPrevented", "(Z)V");
@ -775,6 +776,29 @@ AndroidBridge::GetDPI()
return sDPI;
}
int
AndroidBridge::GetScreenDepth()
{
static int sDepth = 0;
if (sDepth)
return sDepth;
ALOG_BRIDGE("AndroidBridge::GetScreenDepth");
const int DEFAULT_DEPTH = 16;
JNIEnv *env = GetJNIEnv();
if (!env)
return DEFAULT_DEPTH;
AutoLocalJNIFrame jniFrame(env);
sDepth = (int)env->CallStaticIntMethod(mGeckoAppShellClass, jGetScreenDepth);
if (jniFrame.CheckForException()) {
sDepth = 0;
return DEFAULT_DEPTH;
}
return sDepth;
}
void
AndroidBridge::ShowFilePickerForExtensions(nsAString& aFilePath, const nsAString& aExtensions)
{
@ -2682,13 +2706,17 @@ nsresult AndroidBridge::CaptureThumbnail(nsIDOMWindow *window, int32_t bufW, int
nsPresContext::CSSPixelsToAppUnits(srcW / scale),
nsPresContext::CSSPixelsToAppUnits(srcH / scale));
uint32_t stride = bufW * 2 /* 16 bpp */;
bool is24bit = (GetScreenDepth() == 24);
uint32_t stride = bufW * (is24bit ? 4 : 2);
void* data = env->GetDirectBufferAddress(buffer);
if (!data)
return NS_ERROR_FAILURE;
nsRefPtr<gfxImageSurface> surf = new gfxImageSurface(static_cast<unsigned char*>(data), nsIntSize(bufW, bufH), stride, gfxASurface::ImageFormatRGB16_565);
nsRefPtr<gfxImageSurface> surf =
new gfxImageSurface(static_cast<unsigned char*>(data), nsIntSize(bufW, bufH), stride,
is24bit ? gfxASurface::ImageFormatRGB24 :
gfxASurface::ImageFormatRGB16_565);
if (surf->CairoStatus() != 0) {
ALOG_BRIDGE("Error creating gfxImageSurface");
return NS_ERROR_FAILURE;

View File

@ -256,6 +256,7 @@ public:
void CloseNotification(const nsAString& aAlertName);
int GetDPI();
int GetScreenDepth();
void ShowFilePickerForExtensions(nsAString& aFilePath, const nsAString& aExtensions);
void ShowFilePickerForMimeType(nsAString& aFilePath, const nsAString& aMimeType);
@ -482,6 +483,7 @@ protected:
jmethodID jAlertsProgressListener_OnProgress;
jmethodID jCloseNotification;
jmethodID jGetDpi;
jmethodID jGetScreenDepth;
jmethodID jSetFullScreen;
jmethodID jShowInputMethodPicker;
jmethodID jNotifyDefaultPrevented;

View File

@ -45,9 +45,7 @@ nsScreenAndroid::GetAvailRect(int32_t *outLeft, int32_t *outTop, int32_t *outWid
NS_IMETHODIMP
nsScreenAndroid::GetPixelDepth(int32_t *aPixelDepth)
{
// XXX do we need to lie here about 16bpp? Or
// should we actually check and return the right thing?
*aPixelDepth = 16;
*aPixelDepth = AndroidBridge::Bridge()->GetScreenDepth();
return NS_OK;
}

View File

@ -1080,11 +1080,17 @@ nsWindow::OnDraw(AndroidGeckoEvent *ae)
return;
}
int bytesPerPixel = 2;
gfxASurface::gfxImageFormat format = gfxASurface::ImageFormatRGB16_565;
if (AndroidBridge::Bridge()->GetScreenDepth() == 24) {
bytesPerPixel = 4;
format = gfxASurface::ImageFormatRGB24;
}
layers::renderTraceEventStart("Get surface", "424545");
static unsigned char bits2[32 * 32 * 2];
static unsigned char bits2[32 * 32 * 4];
nsRefPtr<gfxImageSurface> targetSurface =
new gfxImageSurface(bits2, gfxIntSize(32, 32), 32 * 2,
gfxASurface::ImageFormatRGB16_565);
new gfxImageSurface(bits2, gfxIntSize(32, 32), 32 * bytesPerPixel, format);
layers::renderTraceEventEnd("Get surface", "424545");
layers::renderTraceEventStart("Widget draw to", "434646");