Bug 692198 - Make Flash on Android draw to bitmap intead of SurfaceView directly

From 718909dd4d8c1b1ffb2e8ea72cc7d75c281e0773 Mon Sep 17 00:00:00 2001

--HG--
extra : rebase_source : 01bc243a06d5470b559c8c892425d7918b5a7de3
This commit is contained in:
James Willcox 2011-10-05 14:44:19 -04:00
Родитель 53f52b3cc9
Коммит 2f1612e0e6
9 изменённых файлов: 206 добавлений и 216 удалений

Просмотреть файл

@ -42,6 +42,7 @@
#include "AndroidBridge.h"
#include "gfxImageSurface.h"
#include "gfxContext.h"
#include "nsNPAPIPluginInstance.h"
#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args)
#define ASSIGN(obj, name) (obj)->name = anp_surface_##name
@ -51,17 +52,11 @@
static struct ANPSurfaceInterfaceJavaGlue {
bool initialized;
jclass geckoAppShellClass;
jclass lockInfoCls;
jmethodID lockSurfaceANP;
jmethodID jUnlockSurfaceANP;
jfieldID jDirtyTop;
jfieldID jDirtyLeft;
jfieldID jDirtyBottom;
jfieldID jDirtyRight;
jclass surfaceInfoCls;
jmethodID getSurfaceInfo;
jfieldID jFormat;
jfieldID jWidth ;
jfieldID jHeight;
jfieldID jBuffer;
} gSurfaceJavaGlue;
#define getClassGlobalRef(env, cname) \
@ -74,23 +69,16 @@ static void init(JNIEnv* env) {
gSurfaceJavaGlue.geckoAppShellClass = mozilla::AndroidBridge::GetGeckoAppShellClass();
jmethodID getClass = env->GetStaticMethodID(gSurfaceJavaGlue.geckoAppShellClass,
"getSurfaceLockInfoClass",
"getSurfaceInfoClass",
"()Ljava/lang/Class;");
gSurfaceJavaGlue.lockInfoCls = (jclass) env->NewGlobalRef(env->CallStaticObjectMethod(gSurfaceJavaGlue.geckoAppShellClass, getClass));
gSurfaceJavaGlue.surfaceInfoCls = (jclass) env->NewGlobalRef(env->CallStaticObjectMethod(gSurfaceJavaGlue.geckoAppShellClass, getClass));
gSurfaceJavaGlue.jDirtyTop = env->GetFieldID(gSurfaceJavaGlue.lockInfoCls, "dirtyTop", "I");
gSurfaceJavaGlue.jDirtyLeft = env->GetFieldID(gSurfaceJavaGlue.lockInfoCls, "dirtyLeft", "I");
gSurfaceJavaGlue.jDirtyBottom = env->GetFieldID(gSurfaceJavaGlue.lockInfoCls, "dirtyBottom", "I");
gSurfaceJavaGlue.jDirtyRight = env->GetFieldID(gSurfaceJavaGlue.lockInfoCls, "dirtyRight", "I");
gSurfaceJavaGlue.jFormat = env->GetFieldID(gSurfaceJavaGlue.surfaceInfoCls, "format", "I");
gSurfaceJavaGlue.jWidth = env->GetFieldID(gSurfaceJavaGlue.surfaceInfoCls, "width", "I");
gSurfaceJavaGlue.jHeight = env->GetFieldID(gSurfaceJavaGlue.surfaceInfoCls, "height", "I");
gSurfaceJavaGlue.jFormat = env->GetFieldID(gSurfaceJavaGlue.lockInfoCls, "format", "I");
gSurfaceJavaGlue.jWidth = env->GetFieldID(gSurfaceJavaGlue.lockInfoCls, "width", "I");
gSurfaceJavaGlue.jHeight = env->GetFieldID(gSurfaceJavaGlue.lockInfoCls, "height", "I");
gSurfaceJavaGlue.jBuffer = env->GetFieldID(gSurfaceJavaGlue.lockInfoCls, "buffer", "Ljava/nio/Buffer;");
gSurfaceJavaGlue.lockSurfaceANP = env->GetStaticMethodID(gSurfaceJavaGlue.geckoAppShellClass, "lockSurfaceANP", "(Landroid/view/SurfaceView;IIII)Lorg/mozilla/gecko/SurfaceLockInfo;");
gSurfaceJavaGlue.jUnlockSurfaceANP = env->GetStaticMethodID(gSurfaceJavaGlue.geckoAppShellClass, "unlockSurfaceANP", "(Landroid/view/SurfaceView;)V");
gSurfaceJavaGlue.getSurfaceInfo = env->GetStaticMethodID(gSurfaceJavaGlue.geckoAppShellClass, "getSurfaceInfo", "(Landroid/view/SurfaceView;)Lorg/mozilla/gecko/SurfaceInfo;");
gSurfaceJavaGlue.initialized = true;
}
@ -103,62 +91,68 @@ static bool anp_lock(JNIEnv* env, jobject surfaceView, ANPBitmap* bitmap, ANPRec
init(env);
jvalue args[5];
args[0].l = surfaceView;
if (dirtyRect) {
args[1].i = dirtyRect->top;
args[2].i = dirtyRect->left;
args[3].i = dirtyRect->bottom;
args[4].i = dirtyRect->right;
LOG("dirty rect: %d, %d, %d, %d", dirtyRect->top, dirtyRect->left, dirtyRect->bottom, dirtyRect->right);
} else {
args[1].i = args[2].i = args[3].i = args[4].i = 0;
}
jobject info = env->CallStaticObjectMethod(gSurfaceJavaGlue.geckoAppShellClass,
gSurfaceJavaGlue.lockSurfaceANP,
surfaceView, args[1].i, args[2].i, args[3].i, args[4].i);
gSurfaceJavaGlue.getSurfaceInfo, surfaceView);
LOG("info: %p", info);
if (!info)
return false;
// the surface may have expanded the dirty region so we must to pass that
// information back to the plugin.
if (dirtyRect) {
dirtyRect->left = env->GetIntField(info, gSurfaceJavaGlue.jDirtyLeft);
dirtyRect->right = env->GetIntField(info, gSurfaceJavaGlue.jDirtyRight);
dirtyRect->top = env->GetIntField(info, gSurfaceJavaGlue.jDirtyTop);
dirtyRect->bottom = env->GetIntField(info, gSurfaceJavaGlue.jDirtyBottom);
LOG("dirty rect: %d, %d, %d, %d", dirtyRect->top, dirtyRect->left, dirtyRect->bottom, dirtyRect->right);
}
bitmap->width = env->GetIntField(info, gSurfaceJavaGlue.jWidth);
bitmap->height = env->GetIntField(info, gSurfaceJavaGlue.jHeight);
if (bitmap->width <= 0 || bitmap->height <= 0)
return false;
int format = env->GetIntField(info, gSurfaceJavaGlue.jFormat);
gfxImageFormat targetFormat;
// format is PixelFormat
if (format & 0x00000001) {
/*
bitmap->format = kRGBA_8888_ANPBitmapFormat;
bitmap->rowBytes = bitmap->width * 4;
}
else if (format & 0x00000004) {
targetFormat = gfxASurface::ImageFormatARGB32;
*/
// We actually can't handle this right now because gfxImageSurface
// doesn't support RGBA32.
LOG("Unable to handle 32bit pixel format");
return false;
} else if (format & 0x00000004) {
bitmap->format = kRGB_565_ANPBitmapFormat;
bitmap->rowBytes = bitmap->width * 2;
}
else {
targetFormat = gfxASurface::ImageFormatRGB16_565;
} else {
LOG("format from glue is unknown %d\n", format);
return false;
}
jobject buf = env->GetObjectField(info, gSurfaceJavaGlue.jBuffer);
bitmap->baseAddr = env->GetDirectBufferAddress(buf);
nsNPAPIPluginInstance* pinst = nsNPAPIPluginInstance::FindByJavaSurface((void*)surfaceView);
if (!pinst) {
LOG("Failed to get plugin instance");
return false;
}
NPRect lockRect;
if (dirtyRect) {
lockRect.top = dirtyRect->top;
lockRect.left = dirtyRect->left;
lockRect.right = dirtyRect->right;
lockRect.bottom = dirtyRect->bottom;
} else {
// No dirty rect, use the whole bitmap
lockRect.top = lockRect.left = 0;
lockRect.right = bitmap->width;
lockRect.bottom = bitmap->height;
}
gfxImageSurface* target = pinst->LockTargetSurface(bitmap->width, bitmap->height, targetFormat, &lockRect);
bitmap->baseAddr = target->Data();
LOG("format: %d, width: %d, height: %d", bitmap->format, bitmap->width, bitmap->height);
env->DeleteLocalRef(info);
env->DeleteLocalRef(buf);
return ( bitmap->width > 0 && bitmap->height > 0 );
return true;
}
static void anp_unlock(JNIEnv* env, jobject surfaceView) {
@ -169,10 +163,13 @@ static void anp_unlock(JNIEnv* env, jobject surfaceView) {
return;
}
init(env);
env->CallStaticVoidMethod(gSurfaceJavaGlue.geckoAppShellClass, gSurfaceJavaGlue.jUnlockSurfaceANP, surfaceView);
LOG("returning from %s", __PRETTY_FUNCTION__);
nsNPAPIPluginInstance* pinst = nsNPAPIPluginInstance::FindByJavaSurface((void*)surfaceView);
if (!pinst) {
LOG("Could not find plugin instance!");
return;
}
pinst->UnlockTargetSurface(true /* invalidate the locked area */);
}
///////////////////////////////////////////////////////////////////////////////

Просмотреть файл

@ -65,7 +65,6 @@
#include "ANPBase.h"
#include <android/log.h>
#include "android_npapi.h"
#include "mozilla/Mutex.h"
#include "mozilla/CondVar.h"
#include "AndroidBridge.h"
#endif
@ -73,6 +72,11 @@
using namespace mozilla;
using namespace mozilla::plugins::parent;
#ifdef ANDROID
#include <map>
static std::map<void*, nsNPAPIPluginInstance*> sSurfaceMap;
#endif
static NS_DEFINE_IID(kIOutputStreamIID, NS_IOUTPUTSTREAM_IID);
static NS_DEFINE_IID(kIPluginStreamListenerIID, NS_IPLUGINSTREAMLISTENER_IID);
@ -89,6 +93,7 @@ nsNPAPIPluginInstance::nsNPAPIPluginInstance(nsNPAPIPlugin* plugin)
#endif
#ifdef ANDROID
mSurface(nsnull),
mTargetSurface(nsnull),
mDrawingModel(0),
#endif
mRunning(NOT_STARTED),
@ -122,6 +127,10 @@ nsNPAPIPluginInstance::nsNPAPIPluginInstance(nsNPAPIPlugin* plugin)
mUsePluginLayersPref = useLayersPref;
}
#ifdef ANDROID
mTargetSurfaceLock = new Mutex("nsNPAPIPluginInstance::SurfaceLock");
#endif
PLUGIN_LOG(PLUGIN_LOG_BASIC, ("nsNPAPIPluginInstance ctor: this=%p\n",this));
}
@ -133,6 +142,22 @@ nsNPAPIPluginInstance::~nsNPAPIPluginInstance()
PR_Free((void *)mMIMEType);
mMIMEType = nsnull;
}
#ifdef ANDROID
if (mSurface) {
sSurfaceMap.erase(mSurface);
}
if (mTargetSurface) {
delete mTargetSurface;
mTargetSurface = nsnull;
}
if (mTargetSurfaceLock) {
delete mTargetSurfaceLock;
mTargetSurfaceLock = nsnull;
}
#endif
}
void
@ -775,9 +800,61 @@ void* nsNPAPIPluginInstance::GetJavaSurface()
nsCOMPtr<SurfaceGetter> sg = new SurfaceGetter(mPlugin->PluginFuncs(), mNPP);
mSurface = sg->GetSurface();
sSurfaceMap[mSurface] = this;
return mSurface;
}
gfxImageSurface*
nsNPAPIPluginInstance::LockTargetSurface()
{
mTargetSurfaceLock->Lock();
return mTargetSurface;
}
gfxImageSurface*
nsNPAPIPluginInstance::LockTargetSurface(PRUint32 aWidth, PRUint32 aHeight, gfxImageFormat aFormat,
NPRect* aRect)
{
mTargetSurfaceLock->Lock();
if (!mTargetSurface ||
mTargetSurface->Width() != aWidth ||
mTargetSurface->Height() != aHeight ||
mTargetSurface->Format() != aFormat) {
if (mTargetSurface) {
delete mTargetSurface;
}
mTargetSurface = new gfxImageSurface(gfxIntSize(aWidth, aHeight), aFormat);
}
mTargetLockRect = *aRect;
return mTargetSurface;
}
void
nsNPAPIPluginInstance::InvalidateTargetRect()
{
InvalidateRect(&mTargetLockRect);
}
void
nsNPAPIPluginInstance::UnlockTargetSurface(bool aInvalidate)
{
mTargetSurfaceLock->Unlock();
if (aInvalidate) {
NS_DispatchToMainThread(NS_NewRunnableMethod(this, &nsNPAPIPluginInstance::InvalidateTargetRect));
}
}
nsNPAPIPluginInstance*
nsNPAPIPluginInstance::FindByJavaSurface(void* aJavaSurface)
{
return sSurfaceMap[aJavaSurface];
}
#endif
nsresult nsNPAPIPluginInstance::GetDrawingModel(PRInt32* aModel)

Просмотреть файл

@ -50,9 +50,16 @@
#include "nsInterfaceHashtable.h"
#include "nsHashKeys.h"
#include "gfxASurface.h"
#include "gfxImageSurface.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/PluginLibrary.h"
#ifdef ANDROID
#include "mozilla/Mutex.h"
#endif
struct JSObject;
class nsPluginStreamListenerPeer; // browser-initiated stream class
@ -148,6 +155,13 @@ public:
#ifdef ANDROID
void SetDrawingModel(PRUint32 aModel);
void* GetJavaSurface();
gfxImageSurface* LockTargetSurface();
gfxImageSurface* LockTargetSurface(PRUint32 aWidth, PRUint32 aHeight, gfxASurface::gfxImageFormat aFormat,
NPRect* aRect);
void UnlockTargetSurface(bool aInvalidate);
static nsNPAPIPluginInstance* FindByJavaSurface(void* aJavaSurface);
#endif
nsresult NewStreamListener(const char* aURL, void* notifyData,
@ -264,7 +278,12 @@ private:
bool mUsePluginLayersPref;
#ifdef ANDROID
void InvalidateTargetRect();
void* mSurface;
gfxImageSurface *mTargetSurface;
mozilla::Mutex* mTargetSurfaceLock;
NPRect mTargetLockRect;
#endif
};

Просмотреть файл

@ -1671,6 +1671,27 @@ void nsPluginInstanceOwner::ScrollPositionDidChange(nscoord aX, nscoord aY)
}
#ifdef ANDROID
void nsPluginInstanceOwner::AddPluginView(const gfxRect& aRect)
{
void* javaSurface = mInstance->GetJavaSurface();
if (!javaSurface)
return;
JNIEnv* env = GetJNIForThread();
jclass cls = env->FindClass("org/mozilla/gecko/GeckoAppShell");
jmethodID method = env->GetStaticMethodID(cls,
"addPluginView",
"(Landroid/view/View;DDDD)V");
env->CallStaticVoidMethod(cls,
method,
javaSurface,
aRect.x,
aRect.y,
aRect.width,
aRect.height);
}
void nsPluginInstanceOwner::RemovePluginView()
{
if (mInstance && mObjectFrame) {
@ -2812,45 +2833,6 @@ void nsPluginInstanceOwner::Paint(const nsRect& aDirtyRect, HPS aHPS)
#ifdef ANDROID
class AndroidPaintEventRunnable : public nsRunnable
{
public:
AndroidPaintEventRunnable(void* aSurface, nsNPAPIPluginInstance* inst, const gfxRect& aFrameRect)
: mSurface(aSurface), mInstance(inst), mFrameRect(aFrameRect) {
}
~AndroidPaintEventRunnable() {
}
NS_IMETHOD Run()
{
LOG("%p - AndroidPaintEventRunnable::Run\n", this);
if (!mInstance || !mSurface)
return NS_OK;
// This needs to happen on the gecko main thread.
JNIEnv* env = GetJNIForThread();
jclass cls = env->FindClass("org/mozilla/gecko/GeckoAppShell");
jmethodID method = env->GetStaticMethodID(cls,
"addPluginView",
"(Landroid/view/View;DDDD)V");
env->CallStaticVoidMethod(cls,
method,
mSurface,
mFrameRect.x,
mFrameRect.y,
mFrameRect.width,
mFrameRect.height);
return NS_OK;
}
private:
void* mSurface;
nsCOMPtr<nsNPAPIPluginInstance> mInstance;
gfxRect mFrameRect;
};
void nsPluginInstanceOwner::Paint(gfxContext* aContext,
const gfxRect& aFrameRect,
const gfxRect& aDirtyRect)
@ -2862,33 +2844,20 @@ void nsPluginInstanceOwner::Paint(gfxContext* aContext,
mInstance->GetDrawingModel(&model);
if (model == kSurface_ANPDrawingModel) {
AddPluginView(aFrameRect);
{
ANPEvent event;
event.inSize = sizeof(ANPEvent);
event.eventType = kLifecycle_ANPEventType;
event.data.lifecycle.action = kOnScreen_ANPLifecycleAction;
mInstance->HandleEvent(&event, nsnull);
gfxImageSurface* pluginSurface = mInstance->LockTargetSurface();
if (!pluginSurface) {
mInstance->UnlockTargetSurface(false);
return;
}
/*
gfxMatrix currentMatrix = aContext->CurrentMatrix();
gfxSize scale = currentMatrix.ScaleFactors(true);
printf_stderr("!!!!!!!! scale!!: %f x %f\n", scale.width, scale.height);
*/
aContext->SetOperator(gfxContext::OPERATOR_SOURCE);
aContext->SetSource(pluginSurface, gfxPoint(aFrameRect.x, aFrameRect.y));
aContext->Clip(aDirtyRect);
aContext->Paint();
JNIEnv* env = GetJNIForThread();
jclass cls = env->FindClass("org/mozilla/gecko/GeckoAppShell");
jmethodID method = env->GetStaticMethodID(cls,
"addPluginView",
"(Landroid/view/View;DDDD)V");
env->CallStaticVoidMethod(cls,
method,
mInstance->GetJavaSurface(),
aFrameRect.x,
aFrameRect.y,
aFrameRect.width,
aFrameRect.height);
mInstance->UnlockTargetSurface(false);
return;
}

Просмотреть файл

@ -309,6 +309,7 @@ private:
void FixUpURLS(const nsString &name, nsAString &value);
#ifdef ANDROID
void AddPluginView(const gfxRect& aRect);
void RemovePluginView();
#endif

Просмотреть файл

@ -1355,10 +1355,7 @@ public class GeckoAppShell
(int)y);
if (GeckoApp.mainLayout.indexOfChild(view) == -1) {
view.setWillNotDraw(false);
if(view instanceof SurfaceView)
((SurfaceView)view).setZOrderOnTop(true);
view.setWillNotDraw(true);
GeckoApp.mainLayout.addView(view, lp);
}
else
@ -1412,16 +1409,9 @@ public class GeckoAppShell
return null;
}
static HashMap<SurfaceView, SurfaceLockInfo> sSufaceMap = new HashMap<SurfaceView, SurfaceLockInfo>();
public static void lockSurfaceANP()
public static SurfaceInfo getSurfaceInfo(SurfaceView sview)
{
Log.i("GeckoAppShell", "other lockSurfaceANP");
}
public static org.mozilla.gecko.SurfaceLockInfo lockSurfaceANP(android.view.SurfaceView sview, int top, int left, int bottom, int right)
{
Log.i("GeckoAppShell", "real lockSurfaceANP " + sview + ", " + top + ", " + left + ", " + bottom + ", " + right);
Log.i("GeckoAppShell", "getSurfaceInfo " + sview);
if (sview == null)
return null;
@ -1435,80 +1425,28 @@ public class GeckoAppShell
}
int n = 0;
if (format == PixelFormat.RGB_565)
if (format == PixelFormat.RGB_565) {
n = 2;
else if (format == PixelFormat.RGBA_8888)
} else if (format == PixelFormat.RGBA_8888) {
n = 4;
if (n == 0)
} else {
Log.i("GeckoAppShell", "Unknown pixel format: " + format);
return null;
SurfaceLockInfo info = sSufaceMap.get(sview);
if (info == null) {
info = new SurfaceLockInfo();
sSufaceMap.put(sview, info);
}
Rect r = new Rect(left, top, right, bottom);
info.canvas = sview.getHolder().lockCanvas(r);
int bufSizeRequired = info.canvas.getWidth() * info.canvas.getHeight() * n;
Log.i("GeckoAppShell", "lockSurfaceANP - bufSizeRequired: " + n + " " + info.canvas.getHeight() + " " + info.canvas.getWidth());
if (info.width != info.canvas.getWidth() || info.height != info.canvas.getHeight() || info.buffer == null || info.buffer.capacity() < bufSizeRequired) {
info.width = info.canvas.getWidth();
info.height = info.canvas.getHeight();
// XXX Bitmaps instead of ByteBuffer
info.buffer = ByteBuffer.allocateDirect(bufSizeRequired); //leak
Log.i("GeckoAppShell", "!!!!!!!!!!! lockSurfaceANP - Allocating buffer! " + bufSizeRequired);
}
info.canvas.drawColor(Color.WHITE, PorterDuff.Mode.CLEAR);
SurfaceInfo info = new SurfaceInfo();
Rect r = sview.getHolder().getSurfaceFrame();
info.width = r.right;
info.height = r.bottom;
info.format = format;
info.dirtyTop = top;
info.dirtyBottom = bottom;
info.dirtyLeft = left;
info.dirtyRight = right;
return info;
}
public static void unlockSurfaceANP(SurfaceView sview) {
SurfaceLockInfo info = sSufaceMap.get(sview);
int n = 0;
Bitmap.Config config;
if (info.format == PixelFormat.RGB_565) {
n = 2;
config = Bitmap.Config.RGB_565;
} else {
n = 4;
config = Bitmap.Config.ARGB_8888;
}
Log.i("GeckoAppShell", "unlockSurfaceANP: " + (info.width * info.height * n));
Bitmap bm = Bitmap.createBitmap(info.width, info.height, config);
bm.copyPixelsFromBuffer(info.buffer);
info.canvas.drawBitmap(bm, 0, 0, null);
sview.getHolder().unlockCanvasAndPost(info.canvas);
}
public static Class getSurfaceLockInfoClass() {
Log.i("GeckoAppShell", "class name: " + SurfaceLockInfo.class.getName());
return SurfaceLockInfo.class;
}
public static Method getSurfaceLockMethod() {
Method[] m = GeckoAppShell.class.getMethods();
for (int i = 0; i < m.length; i++) {
if (m[i].getName().equals("lockSurfaceANP"))
return m[i];
}
return null;
public static Class getSurfaceInfoClass() {
Log.i("GeckoAppShell", "class name: " + SurfaceInfo.class.getName());
return SurfaceInfo.class;
}
static native void executeNextRunnable();

Просмотреть файл

@ -53,7 +53,7 @@ JAVAFILES = \
GeckoSurfaceView.java \
GeckoInputConnection.java \
AlertNotification.java \
SurfaceLockInfo.java \
SurfaceInfo.java \
$(NULL)
PROCESSEDJAVAFILES = \

Просмотреть файл

@ -0,0 +1,7 @@
package org.mozilla.gecko;
public class SurfaceInfo {
public int format;
public int width;
public int height;
}

Просмотреть файл

@ -1,18 +0,0 @@
package org.mozilla.gecko;
import android.graphics.Canvas;
import java.nio.Buffer;
public class SurfaceLockInfo {
public int dirtyTop;
public int dirtyLeft;
public int dirtyRight;
public int dirtyBottom;
public int bpr;
public int format;
public int width;
public int height;
public Buffer buffer;
public Canvas canvas;
}