bug 726930 - speed up tab thumbnails r=mfinkle

This commit is contained in:
Brad Lassey 2012-02-17 10:52:26 -08:00
parent 99a084de31
commit 585ae3af5b
11 changed files with 105 additions and 87 deletions

View File

@ -626,25 +626,7 @@ abstract public class GeckoApp
int sh = forceBigSceenshot ? mSoftwareLayerClient.getHeight(): tab.getMinScreenshotHeight();
int dw = forceBigSceenshot ? sw : tab.getThumbnailWidth();
int dh = forceBigSceenshot ? sh : tab.getThumbnailHeight();
try {
JSONObject message = new JSONObject();
message.put("tabID", tab.getId());
JSONObject source = new JSONObject();
source.put("width", sw);
source.put("height", sh);
message.put("source", source);
JSONObject destination = new JSONObject();
destination.put("width", dw);
destination.put("height", dh);
message.put("destination", destination);
String json = message.toString();
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Tab:Screenshot", json));
} catch(JSONException jsonEx) {
Log.w(LOGTAG, "Constructing the JSON data for Tab:Screenshot event failed", jsonEx);
}
GeckoAppShell.sendEventToGecko(GeckoEvent.createScreenshotEvent(tab.getId(), sw, sh, dw, dh));
}
}

View File

@ -566,12 +566,14 @@ public class GeckoAppShell
mInputConnection.notifyIMEChange(text, start, end, newEnd);
}
public static void notifyScreenShot(ByteBuffer data, int tabId, int width, int height) {
final Bitmap b = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
b.copyPixelsFromBuffer(data);
final Tab tab = Tabs.getInstance().getTab(tabId);
public static void notifyScreenShot(final ByteBuffer data, final int tabId,
final int width, final int height) {
getHandler().post(new Runnable() {
public void run() {
Bitmap b = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
b.copyPixelsFromBuffer(data);
freeDirectBuffer(data);
final Tab tab = Tabs.getInstance().getTab(tabId);
GeckoApp.mAppContext.processThumbnail(tab, b, null);
}
});

View File

@ -88,6 +88,7 @@ public class GeckoEvent {
private static final int NETWORK_CHANGED = 22;
private static final int PROXIMITY_EVENT = 23;
private static final int ACTIVITY_RESUMING = 24;
private static final int SCREENSHOT = 25;
public static final int IME_COMPOSITION_END = 0;
public static final int IME_COMPOSITION_BEGIN = 1;
@ -399,4 +400,13 @@ public class GeckoEvent {
event.mCanBeMetered = canBeMetered;
return event;
}
public static GeckoEvent createScreenshotEvent(int tabId, int sw, int sh, int dw, int dh) {
GeckoEvent event = new GeckoEvent(SCREENSHOT);
event.mPoints = new Point[2];
event.mPoints[0] = new Point(sw, sh);
event.mPoints[1] = new Point(dw, dh);
event.mMetaState = tabId;
return event;
}
}

View File

@ -202,11 +202,12 @@ var BrowserApp = {
getBridge().setDrawMetadataProvider(MetadataProvider);
getBridge().browserApp = this;
Services.obs.addObserver(this, "Tab:Add", false);
Services.obs.addObserver(this, "Tab:Load", false);
Services.obs.addObserver(this, "Tab:Selected", false);
Services.obs.addObserver(this, "Tab:Closed", false);
Services.obs.addObserver(this, "Tab:Screenshot", false);
Services.obs.addObserver(this, "Session:Back", false);
Services.obs.addObserver(this, "Session:Forward", false);
Services.obs.addObserver(this, "Session:Reload", false);
@ -557,36 +558,6 @@ var BrowserApp = {
this._tabs.splice(this._tabs.indexOf(aTab), 1);
},
screenshotQueue: null,
screenshotTab: function screenshotTab(aData) {
if (this.screenshotQueue == null) {
this.screenShotQueue = [];
this.doScreenshotTab(aData);
} else {
this.screenshotQueue.push(aData);
}
},
doNextScreenshot: function() {
if (this.screenshotQueue == null || this.screenshotQueue.length == 0) {
this.screenshotQueue = null;
return;
}
let data = this.screenshotQueue.pop();
if (data == null) {
this.screenshotQueue = null;
return;
}
this.doScreenshotTab(data);
},
doScreenshotTab: function doScreenshotTab(aData) {
let json = JSON.parse(aData);
let tab = this.getTabForId(parseInt(json.tabID));
tab.screenshot(json.source, json.destination);
},
// Use this method to select a tab from JS. This method sends a message
// to Java to select the tab in the Java UI (we'll get a Tab:Selected message
// back from Java when that happens).
@ -964,10 +935,6 @@ var BrowserApp = {
this._handleTabSelected(this.getTabForId(parseInt(aData)));
} else if (aTopic == "Tab:Closed") {
this._handleTabClosed(this.getTabForId(parseInt(aData)));
} else if (aTopic == "Tab:Screenshot") {
this.screenshotTab(aData);
} else if (aTopic == "Tab:Screenshot:Cancel") {
this.screenshotQueue = null;
} else if (aTopic == "Browser:Quit") {
this.quit();
} else if (aTopic == "SaveAs:PDF") {
@ -1002,7 +969,16 @@ var BrowserApp = {
delete this.defaultBrowserWidth;
let width = Services.prefs.getIntPref("browser.viewport.desktopWidth");
return this.defaultBrowserWidth = width;
},
// nsIAndroidBrowserApp
getWindowForTab: function(tabId) {
let tab = this.getTabForId(tabId);
if (!tab.browser)
return null;
return tab.browser.contentWindow;
}
};
var NativeWindow = {
@ -1655,16 +1631,6 @@ Tab.prototype = {
this.updateTransform();
},
screenshot: function(aSrc, aDst) {
if (!this.browser || !this.browser.contentWindow)
return;
getBridge().takeScreenshot(this.browser.contentWindow, 0, 0, aSrc.width, aSrc.height, aDst.width, aDst.height, this.id);
Services.tm.mainThread.dispatch(function() {
BrowserApp.doNextScreenshot()
}, Ci.nsIThread.DISPATCH_NORMAL);
},
updateTransform: function() {
let hasZoom = (Math.abs(this._viewport.zoom - 1.0) >= 1e-6);
let x = this._viewport.offsetX + Math.round(-this.viewportExcess.x * this._viewport.zoom);

View File

@ -1967,8 +1967,27 @@ AndroidBridge::HideSurface(jobject surface)
}
/* void takeScreenshot (in nsIDOMWindow win, in PRInt32 srcX, in PRInt32 srcY, in PRInt32 srcW, in PRInt32 srcH, in PRInt32 dstX, in PRInt32 dstY, in PRInt32 dstW, in PRInt32 dstH, in AString color); */
NS_IMETHODIMP nsAndroidBridge::TakeScreenshot(nsIDOMWindow *window, PRInt32 srcX, PRInt32 srcY, PRInt32 srcW, PRInt32 srcH, PRInt32 dstW, PRInt32 dstH, PRInt32 tabId)
/* attribute nsIAndroidBrowserApp browserApp; */
NS_IMETHODIMP nsAndroidBridge::GetBrowserApp(nsIAndroidBrowserApp * *aBrowserApp)
{
if (nsAppShell::gAppShell)
nsAppShell::gAppShell->GetBrowserApp(aBrowserApp);
return NS_OK;
}
NS_IMETHODIMP nsAndroidBridge::SetBrowserApp(nsIAndroidBrowserApp *aBrowserApp)
{
if (nsAppShell::gAppShell)
nsAppShell::gAppShell->SetBrowserApp(aBrowserApp);
return NS_OK;
}
extern "C"
__attribute__ ((visibility("default")))
jobject JNICALL
Java_org_mozilla_gecko_GeckoAppShell_allocateDirectBuffer(JNIEnv *jenv, jclass, jlong size);
nsresult AndroidBridge::TakeScreenshot(nsIDOMWindow *window, PRInt32 srcX, PRInt32 srcY, PRInt32 srcW, PRInt32 srcH, PRInt32 dstW, PRInt32 dstH, PRInt32 tabId)
{
nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(window);
if (!win)
@ -1989,22 +2008,23 @@ NS_IMETHODIMP nsAndroidBridge::TakeScreenshot(nsIDOMWindow *window, PRInt32 srcX
nsPresContext::CSSPixelsToAppUnits(srcW),
nsPresContext::CSSPixelsToAppUnits(srcH));
nsRefPtr<gfxImageSurface> surf = new gfxImageSurface(nsIntSize(dstW, dstH), gfxASurface::ImageFormatRGB16_565);
JNIEnv* jenv = AndroidBridge::GetJNIEnv();
if (!jenv)
return NS_OK;
PRUint32 stride = dstW * 2;
PRUint32 bufferSize = dstH * stride;
jobject buffer = Java_org_mozilla_gecko_GeckoAppShell_allocateDirectBuffer(jenv, NULL, bufferSize);
if (!buffer)
return NS_OK;
void* data = jenv->GetDirectBufferAddress(buffer);
nsRefPtr<gfxImageSurface> surf = new gfxImageSurface(static_cast<unsigned char*>(data), nsIntSize(dstW, dstH), stride, gfxASurface::ImageFormatRGB16_565);
nsRefPtr<gfxContext> context = new gfxContext(surf);
nsresult rv = presShell->RenderDocument(r, renderDocFlags, bgColor, context);
NS_ENSURE_SUCCESS(rv, rv);
AndroidBridge::Bridge()->NotifyScreenshot(surf->Data(), surf->GetDataSize(), tabId, dstW, dstH);
AndroidBridge::AutoLocalJNIFrame jniFrame(jenv, 1);
jenv->CallStaticVoidMethod(AndroidBridge::Bridge()->mGeckoAppShellClass, AndroidBridge::Bridge()->jNotifyScreenShot, buffer, tabId, dstW, dstH);
return NS_OK;
}
void AndroidBridge::NotifyScreenshot(unsigned char* data, int size, int tabId, int width, int height)
{
JNIEnv* jenv = GetJNIEnv();
if (!jenv)
return;
AutoLocalJNIFrame jniFrame(jenv, 1);
jobject buffer = jenv->NewDirectByteBuffer(data, size);
if (!buffer)
return;
jenv->CallStaticVoidMethod(mGeckoAppShellClass, jNotifyScreenShot, buffer, tabId, width, height);
}

View File

@ -156,7 +156,7 @@ public:
static void NotifyIMEChange(const PRUnichar *aText, PRUint32 aTextLen, int aStart, int aEnd, int aNewEnd);
void NotifyScreenshot(unsigned char* data, int size, int tabId, int width, int height);
nsresult TakeScreenshot(nsIDOMWindow *window, PRInt32 srcX, PRInt32 srcY, PRInt32 srcW, PRInt32 srcH, PRInt32 dstW, PRInt32 dstH, PRInt32 tabId);
void AcknowledgeEventSync();

View File

@ -555,6 +555,11 @@ AndroidGeckoEvent::Init(JNIEnv *jenv, jobject jobj)
break;
}
case SCREENSHOT: {
mMetaState = jenv->GetIntField(jobj, jMetaStateField);
ReadPointArray(mPoints, jenv, jPoints, 2);
}
default:
break;
}

View File

@ -570,6 +570,7 @@ public:
NETWORK_CHANGED = 22,
PROXIMITY_EVENT = 23,
ACTIVITY_RESUMING = 24,
SCREENSHOT = 25,
dummy_java_enum_list_end
};

View File

@ -434,6 +434,23 @@ nsAppShell::ProcessNextNativeEvent(bool mayWait)
break;
}
case AndroidGeckoEvent::SCREENSHOT: {
if (!mBrowserApp)
break;
AndroidBridge* bridge = AndroidBridge::Bridge();
if (!bridge)
break;
nsCOMPtr<nsIDOMWindow> domWindow;
mBrowserApp->GetWindowForTab(curEvent->MetaState(), getter_AddRefs(domWindow));
nsTArray<nsIntPoint> points = curEvent->Points();
NS_ASSERTION(points.Length() != 2, "Screenshot event does not have enough coordinates");
if (domWindow)
bridge->TakeScreenshot(domWindow, 0, 0, points[0].x, points[0].y, points[1].x, points[1].y, curEvent->MetaState());
break;
}
case AndroidGeckoEvent::VIEWPORT:
case AndroidGeckoEvent::BROADCAST: {

View File

@ -45,6 +45,7 @@
#include "nsCOMPtr.h"
#include "nsTArray.h"
#include "nsInterfaceHashtable.h"
#include "nsIAndroidBridge.h"
namespace mozilla {
class AndroidGeckoEvent;
@ -84,6 +85,14 @@ public:
void NotifyObservers(nsISupports *aSupports, const char *aTopic, const PRUnichar *aData);
void ResendLastResizeEvent(nsWindow* aDest);
void SetBrowserApp(nsIAndroidBrowserApp* aBrowserApp) {
mBrowserApp = aBrowserApp;
}
void GetBrowserApp(nsIAndroidBrowserApp* *aBrowserApp) {
*aBrowserApp = mBrowserApp;
}
protected:
virtual void ScheduleNativeEventCallback();
virtual ~nsAppShell();
@ -99,6 +108,8 @@ protected:
mozilla::AndroidGeckoEvent *PopNextEvent();
mozilla::AndroidGeckoEvent *PeekNextEvent();
nsCOMPtr<nsIAndroidBrowserApp> mBrowserApp;
};
#endif // nsAppShell_h__

View File

@ -12,11 +12,15 @@ interface nsIAndroidDrawMetadataProvider : nsISupports {
boolean paintingSuppressed();
};
[scriptable, uuid(d10377b4-1c90-493a-a532-63cb3f16ee2b)]
interface nsIAndroidBrowserApp : nsISupports {
nsIDOMWindow getWindowForTab(in PRInt32 tabId);
};
[scriptable, uuid(7dd8441a-4f38-49b2-bd90-da69d02a96cf)]
interface nsIAndroidBridge : nsISupports
{
AString handleGeckoMessage(in AString message);
void setDrawMetadataProvider(in nsIAndroidDrawMetadataProvider provider);
void takeScreenshot(in nsIDOMWindow win, in PRInt32 srcX, in PRInt32 srcY, in PRInt32 srcW, in PRInt32 srcH,
in PRInt32 dstW, in PRInt32 dstH, in PRInt32 tabId);
attribute nsIAndroidBrowserApp browserApp;
};