gecko/mobile/android/base/gfx/GeckoSoftwareLayerClient.java
Kartikaya Gupta 0d69c9733d Bug 704950 - Remove java guess to reset viewport [r=Cwiiis]
This removes the "mNewContent" java-side guess as to when
gecko has loaded new content.
2011-11-29 09:58:22 -05:00

249 lines
9.0 KiB
Java

/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Android code.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2009-2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Patrick Walton <pcwalton@mozilla.com>
* Chris Lord <chrislord.net@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
package org.mozilla.gecko.gfx;
import org.mozilla.gecko.gfx.CairoImage;
import org.mozilla.gecko.gfx.IntSize;
import org.mozilla.gecko.gfx.LayerClient;
import org.mozilla.gecko.gfx.LayerController;
import org.mozilla.gecko.gfx.LayerRenderer;
import org.mozilla.gecko.gfx.PointUtils;
import org.mozilla.gecko.gfx.SingleTileLayer;
import org.mozilla.gecko.FloatUtils;
import org.mozilla.gecko.GeckoApp;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.GeckoEvent;
import android.content.Context;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.DisplayMetrics;
import android.util.Log;
import org.json.JSONException;
import org.json.JSONObject;
import java.nio.ByteBuffer;
/**
* Transfers a software-rendered Gecko to an ImageLayer so that it can be rendered by our
* compositor.
*
* TODO: Throttle down Gecko's priority when we pan and zoom.
*/
public class GeckoSoftwareLayerClient extends LayerClient {
private static final String LOGTAG = "GeckoSoftwareLayerClient";
private Context mContext;
private int mWidth, mHeight, mFormat;
private IntSize mScreenSize, mViewportSize;
private ByteBuffer mBuffer;
private final SingleTileLayer mTileLayer;
/* The viewport rect that Gecko is currently displaying. */
private ViewportMetrics mGeckoViewport;
private CairoImage mCairoImage;
private static final long MIN_VIEWPORT_CHANGE_DELAY = 350L;
private long mLastViewportChangeTime;
private boolean mPendingViewportAdjust;
public GeckoSoftwareLayerClient(Context context) {
mContext = context;
mWidth = LayerController.TILE_WIDTH;
mHeight = LayerController.TILE_HEIGHT;
mFormat = CairoImage.FORMAT_RGB16_565;
mScreenSize = new IntSize(1, 1);
mBuffer = ByteBuffer.allocateDirect(mWidth * mHeight * 2);
mCairoImage = new CairoImage() {
@Override
public ByteBuffer getBuffer() { return mBuffer; }
@Override
public int getWidth() { return mWidth; }
@Override
public int getHeight() { return mHeight; }
@Override
public int getFormat() { return mFormat; }
};
mTileLayer = new SingleTileLayer(mCairoImage);
}
/** Attaches the root layer to the layer controller so that Gecko appears. */
@Override
public void setLayerController(LayerController layerController) {
super.setLayerController(layerController);
layerController.setRoot(mTileLayer);
if (mGeckoViewport != null)
layerController.setViewportMetrics(mGeckoViewport);
geometryChanged();
}
public void beginDrawing() {
mTileLayer.beginTransaction();
}
/*
* TODO: Would be cleaner if this took an android.graphics.Rect instead, but that would require
* a little more JNI magic.
*/
public void endDrawing(int x, int y, int width, int height, String metadata) {
try {
try {
JSONObject metadataObject = new JSONObject(metadata);
mGeckoViewport = new ViewportMetrics(metadataObject);
mTileLayer.setOrigin(PointUtils.round(mGeckoViewport.getDisplayportOrigin()));
mTileLayer.setResolution(mGeckoViewport.getZoomFactor());
// Make sure LayerController metrics changes only happen in the
// UI thread.
final LayerController controller = getLayerController();
if (controller != null) {
controller.post(new Runnable() {
@Override
public void run() {
// Don't adjust page size when zooming unless zoom levels are
// approximately equal.
if (FloatUtils.fuzzyEquals(controller.getZoomFactor(), mGeckoViewport.getZoomFactor()))
controller.setPageSize(mGeckoViewport.getPageSize());
}
});
}
} catch (JSONException e) {
throw new RuntimeException(e);
}
Rect rect = new Rect(x, y, x + width, y + height);
mTileLayer.invalidate(rect);
} finally {
mTileLayer.endTransaction();
}
}
public ViewportMetrics getGeckoViewportMetrics() {
// Return a copy, as we modify this inside the Gecko thread
if (mGeckoViewport != null)
return new ViewportMetrics(mGeckoViewport);
return null;
}
/** Returns the back buffer. This function is for Gecko to use. */
public ByteBuffer lockBuffer() {
return mBuffer;
}
/**
* Gecko calls this function to signal that it is done with the back buffer. After this call,
* it is forbidden for Gecko to touch the buffer.
*/
public void unlockBuffer() {
/* no-op */
}
@Override
public void geometryChanged() {
/* Let Gecko know if the screensize has changed */
DisplayMetrics metrics = new DisplayMetrics();
GeckoApp.mAppContext.getWindowManager().getDefaultDisplay().getMetrics(metrics);
if (metrics.widthPixels != mScreenSize.width ||
metrics.heightPixels != mScreenSize.height) {
mScreenSize = new IntSize(metrics.widthPixels, metrics.heightPixels);
Log.i(LOGTAG, "Screen-size changed to " + mScreenSize);
GeckoEvent event = new GeckoEvent(GeckoEvent.SIZE_CHANGED,
LayerController.TILE_WIDTH, LayerController.TILE_HEIGHT,
metrics.widthPixels, metrics.heightPixels);
GeckoAppShell.sendEventToGecko(event);
}
render();
}
@Override
public void render() {
adjustViewportWithThrottling();
}
private void adjustViewportWithThrottling() {
if (!getLayerController().getRedrawHint())
return;
if (mPendingViewportAdjust)
return;
long timeDelta = System.currentTimeMillis() - mLastViewportChangeTime;
if (timeDelta < MIN_VIEWPORT_CHANGE_DELAY) {
getLayerController().getView().postDelayed(
new Runnable() {
public void run() {
mPendingViewportAdjust = false;
adjustViewport();
}
}, MIN_VIEWPORT_CHANGE_DELAY - timeDelta);
mPendingViewportAdjust = true;
return;
}
adjustViewport();
}
private void adjustViewport() {
Log.i(LOGTAG, "Adjusting viewport");
ViewportMetrics viewportMetrics =
new ViewportMetrics(getLayerController().getViewportMetrics());
PointF viewportOffset = viewportMetrics.getOptimumViewportOffset();
viewportMetrics.setViewportOffset(viewportOffset);
viewportMetrics.setViewport(viewportMetrics.getClampedViewport());
GeckoEvent event = new GeckoEvent("Viewport:Change", viewportMetrics.toJSON());
GeckoAppShell.sendEventToGecko(event);
mLastViewportChangeTime = System.currentTimeMillis();
}
}