Bug 724928 - Tell Gecko not to draw areas we aren't interested in. r=kats

Alter GeckoSoftwareLayerClient.beginDrawing so that it can return a rectangle
of the buffer that it's interested in. Gecko then uses this to clip the dirty
region, which often saves on unnecessary drawing during flings.
This commit is contained in:
Chris Lord 2012-02-09 17:28:10 +00:00
parent cdc622f177
commit 5e69f80ec8
5 changed files with 91 additions and 29 deletions

View File

@ -189,7 +189,8 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL
return true;
}
public boolean beginDrawing(int width, int height, int tileWidth, int tileHeight, String metadata, boolean hasDirectTexture) {
public Rect beginDrawing(int width, int height, int tileWidth, int tileHeight,
String metadata, boolean hasDirectTexture) {
setHasDirectTexture(hasDirectTexture);
// Make sure the tile-size matches. If it doesn't, we could crash trying
@ -197,15 +198,17 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL
if (mHasDirectTexture) {
if (tileWidth != 0 || tileHeight != 0) {
Log.e(LOGTAG, "Aborting draw, incorrect tile size of " + tileWidth + "x" + tileHeight);
return false;
return null;
}
} else {
if (tileWidth != TILE_SIZE.width || tileHeight != TILE_SIZE.height) {
Log.e(LOGTAG, "Aborting draw, incorrect tile size of " + tileWidth + "x" + tileHeight);
return false;
return null;
}
}
LayerController controller = getLayerController();
try {
JSONObject viewportObject = new JSONObject(metadata);
mNewGeckoViewport = new ViewportMetrics(viewportObject);
@ -213,12 +216,49 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL
// Update the background color, if it's present.
String backgroundColorString = viewportObject.optString("backgroundColor");
if (backgroundColorString != null) {
LayerController controller = getLayerController();
controller.setCheckerboardColor(parseColorFromGecko(backgroundColorString));
}
} catch (JSONException e) {
Log.e(LOGTAG, "Aborting draw, bad viewport description: " + metadata);
return false;
return null;
}
// Make sure we don't spend time painting areas we aren't interested in.
// Only do this if the Gecko viewport isn't going to override our viewport.
Rect bufferRect = new Rect(0, 0, width, height);
if (!mUpdateViewportOnEndDraw) {
// First, find out our ideal displayport. We do this by taking the
// clamped viewport origin and taking away the optimum viewport offset.
// This would be what we would send to Gecko if adjustViewport were
// called now.
ViewportMetrics currentMetrics = controller.getViewportMetrics();
PointF currentBestOrigin = RectUtils.getOrigin(currentMetrics.getClampedViewport());
PointF viewportOffset = currentMetrics.getOptimumViewportOffset(new IntSize(width, height));
currentBestOrigin.offset(-viewportOffset.x, -viewportOffset.y);
Rect currentRect = RectUtils.round(new RectF(currentBestOrigin.x, currentBestOrigin.y,
currentBestOrigin.x + width, currentBestOrigin.y + height));
// Second, store Gecko's displayport.
PointF currentOrigin = mNewGeckoViewport.getDisplayportOrigin();
bufferRect = RectUtils.round(new RectF(currentOrigin.x, currentOrigin.y,
currentOrigin.x + width, currentOrigin.y + height));
// Take the intersection of the two as the area we're interested in rendering.
if (!bufferRect.intersect(currentRect)) {
// If there's no intersection, we have no need to render anything,
// but make sure to update the viewport size.
beginTransaction(mTileLayer);
try {
updateViewport(true);
} finally {
endTransaction(mTileLayer);
}
return null;
}
bufferRect.offset(Math.round(-currentOrigin.x), Math.round(-currentOrigin.y));
}
beginTransaction(mTileLayer);
@ -227,26 +267,23 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL
if (mBufferSize.width != width || mBufferSize.height != height) {
mBufferSize = new IntSize(width, height);
// We only need to allocate buffer memory if we're using MultiTileLayer.
if (!(mTileLayer instanceof MultiTileLayer)) {
return true;
}
// Reallocate the buffer if necessary
int bpp = CairoUtils.bitsPerPixelForCairoFormat(mFormat) / 8;
int size = mBufferSize.getArea() * bpp;
if (mBuffer == null || mBuffer.capacity() != size) {
// Free the old buffer
if (mBuffer != null) {
GeckoAppShell.freeDirectBuffer(mBuffer);
mBuffer = null;
}
if (mTileLayer instanceof MultiTileLayer) {
int bpp = CairoUtils.bitsPerPixelForCairoFormat(mFormat) / 8;
int size = mBufferSize.getArea() * bpp;
if (mBuffer == null || mBuffer.capacity() != size) {
// Free the old buffer
if (mBuffer != null) {
GeckoAppShell.freeDirectBuffer(mBuffer);
mBuffer = null;
}
mBuffer = GeckoAppShell.allocateDirectBuffer(size);
mBuffer = GeckoAppShell.allocateDirectBuffer(size);
}
}
}
return true;
return bufferRect;
}
private void updateViewport(final boolean onlyUpdatePageSize) {

View File

@ -38,6 +38,8 @@
package org.mozilla.gecko.gfx;
import org.mozilla.gecko.FloatUtils;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import org.json.JSONException;
@ -109,6 +111,14 @@ public final class RectUtils {
return new IntSize(rect.width(), rect.height());
}
public static Point getOrigin(Rect rect) {
return new Point(rect.left, rect.top);
}
public static PointF getOrigin(RectF rect) {
return new PointF(rect.left, rect.top);
}
/*
* Returns the rect that represents a linear transition between `from` and `to` at time `t`,
* which is on the scale [0, 1).

View File

@ -331,7 +331,7 @@ AndroidGeckoSoftwareLayerClient::InitGeckoSoftwareLayerClientClass(JNIEnv *jEnv)
jLockBufferMethod = getMethod("lockBuffer", "()Ljava/nio/ByteBuffer;");
jUnlockBufferMethod = getMethod("unlockBuffer", "()V");
jBeginDrawingMethod = getMethod("beginDrawing", "(IIIILjava/lang/String;Z)Z");
jBeginDrawingMethod = getMethod("beginDrawing", "(IIIILjava/lang/String;Z)Landroid/graphics/Rect;");
jEndDrawingMethod = getMethod("endDrawing", "(IIII)V");
#endif
}
@ -392,8 +392,8 @@ AndroidGeckoEvent::ReadRectField(JNIEnv *jenv)
if (!r.isNull()) {
mRect.SetRect(r.Left(),
r.Top(),
r.Right() - r.Left(),
r.Bottom() - r.Top());
r.Width(),
r.Height());
} else {
mRect.SetEmpty();
}
@ -690,7 +690,7 @@ AndroidGeckoSoftwareLayerClient::UnlockBuffer()
}
bool
AndroidGeckoSoftwareLayerClient::BeginDrawing(int aWidth, int aHeight, int aTileWidth, int aTileHeight, const nsAString &aMetadata, bool aHasDirectTexture)
AndroidGeckoSoftwareLayerClient::BeginDrawing(int aWidth, int aHeight, int aTileWidth, int aTileHeight, nsIntRect &aDirtyRect, const nsAString &aMetadata, bool aHasDirectTexture)
{
NS_ASSERTION(!isNull(), "BeginDrawing() called on null software layer client!");
JNIEnv *env = AndroidBridge::GetJNIEnv();
@ -699,7 +699,20 @@ AndroidGeckoSoftwareLayerClient::BeginDrawing(int aWidth, int aHeight, int aTile
AndroidBridge::AutoLocalJNIFrame(env, 1);
jstring jMetadata = env->NewString(nsPromiseFlatString(aMetadata).get(), aMetadata.Length());
return env->CallBooleanMethod(wrapped_obj, jBeginDrawingMethod, aWidth, aHeight, aTileWidth, aTileHeight, jMetadata, aHasDirectTexture);
jobject rectObject = env->CallObjectMethod(wrapped_obj, jBeginDrawingMethod,
aWidth, aHeight, aTileWidth, aTileHeight,
jMetadata, aHasDirectTexture);
if (rectObject == nsnull)
return false;
AndroidRect rect(env, rectObject);
nsIntRect newDirtyRect = aDirtyRect.Intersect(nsIntRect(rect.Top(), rect.Left(),
rect.Width(), rect.Height()));
aDirtyRect.SetRect(newDirtyRect.x, newDirtyRect.y, newDirtyRect.width, newDirtyRect.height);
return true;
}
void

View File

@ -135,6 +135,8 @@ public:
int Left() { return mLeft; }
int Right() { return mRight; }
int Top() { return mTop; }
int Width() { return mRight - mLeft; }
int Height() { return mBottom - mTop; }
protected:
int mBottom;
@ -161,7 +163,7 @@ public:
jobject LockBuffer();
unsigned char *LockBufferBits();
void UnlockBuffer();
bool BeginDrawing(int aWidth, int aHeight, int aTileWidth, int aTileHeight, const nsAString &aMetadata, bool aHasDirectTexture);
bool BeginDrawing(int aWidth, int aHeight, int aTileWidth, int aTileHeight, nsIntRect &aDirtyRect, const nsAString &aMetadata, bool aHasDirectTexture);
void EndDrawing(const nsIntRect &aRect);
private:

View File

@ -1208,16 +1208,16 @@ nsWindow::OnDraw(AndroidGeckoEvent *ae)
metadataProvider->GetDrawMetadata(metadata);
}
nsIntRect dirtyRect = ae->Rect().Intersect(nsIntRect(0, 0, gAndroidBounds.width, gAndroidBounds.height));
AndroidGeckoSoftwareLayerClient &client =
AndroidBridge::Bridge()->GetSoftwareLayerClient();
if (!client.BeginDrawing(gAndroidBounds.width, gAndroidBounds.height,
gAndroidTileSize.width, gAndroidTileSize.height,
metadata, HasDirectTexture())) {
dirtyRect, metadata, HasDirectTexture())) {
return;
}
nsIntRect dirtyRect = ae->Rect().Intersect(nsIntRect(0, 0, gAndroidBounds.width, gAndroidBounds.height));
unsigned char *bits = NULL;
if (HasDirectTexture()) {
if (sDirectTexture->Width() != gAndroidBounds.width ||