author | Kartikaya Gupta <kgupta@mozilla.com> |
Tue, 20 Mar 2012 00:07:42 -0400 | |
changeset 89804 | 22af7bc45a186d51c4d940a49bfff7d32aba7ad6 |
parent 89803 | f93f7553317f5ac91433083612f783da14277342 |
child 89805 | ee554888d071ad7bde8d25155747f4ff6aea9c1b |
child 89806 | 46c5015550aff585c8b24e3e83e5472d97a994ae |
push id | 22282 |
push user | mlamouri@mozilla.com |
push date | Tue, 20 Mar 2012 10:40:32 +0000 |
treeherder | mozilla-central@ee554888d071 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | Cwiiis |
bugs | 731603 |
milestone | 14.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/mobile/android/base/gfx/GeckoLayerClient.java +++ b/mobile/android/base/gfx/GeckoLayerClient.java @@ -68,26 +68,20 @@ public class GeckoLayerClient implements private IntSize mScreenSize; private IntSize mWindowSize; private RectF mDisplayPort; private RectF mReturnDisplayPort; private VirtualLayer mRootLayer; - /* The viewport that Gecko is currently displaying. */ + /* The Gecko viewport as per the UI thread. Must be touched only on the UI thread. */ private ViewportMetrics mGeckoViewport; /* - * The display port that Gecko is currently displaying. This is stored only - * to avoid having to create a Rect on every composition. - */ - private Rect mGeckoDisplayPort; - - /* * The viewport metrics being used to draw the current frame. This is only * accessed by the compositor thread, and so needs no synchronisation. */ private ImmutableViewportMetrics mFrameMetrics; private String mLastCheckerboardColor; /* Used by robocop for testing purposes */ @@ -97,17 +91,16 @@ public class GeckoLayerClient implements private ViewTransform mCurrentViewTransform; public GeckoLayerClient(Context context) { // we can fill these in with dummy values because they are always written // to before being read mScreenSize = new IntSize(0, 0); mWindowSize = new IntSize(0, 0); mDisplayPort = new RectF(); - mGeckoDisplayPort = new Rect(); mCurrentViewTransform = new ViewTransform(0, 0, 1); } /** Attaches the root layer to the layer controller so that Gecko appears. */ void setLayerController(LayerController layerController) { LayerView view = layerController.getView(); mLayerController = layerController; @@ -121,37 +114,16 @@ public class GeckoLayerClient implements view.setListener(this); view.setLayerRenderer(mLayerRenderer); layerController.setRoot(mRootLayer); sendResizeEventIfNecessary(true); } - /** This function is invoked by Gecko via JNI; be careful when modifying signature. */ - public boolean beginDrawing(int width, int height, String metadata) { - try { - JSONObject viewportObject = new JSONObject(metadata); - mGeckoViewport = new ViewportMetrics(viewportObject); - } catch (JSONException e) { - Log.e(LOGTAG, "Aborting draw, bad viewport description: " + metadata); - return false; - } - - return true; - } - - /** This function is invoked by Gecko via JNI; be careful when modifying signature. */ - public void endDrawing() { - synchronized (mLayerController) { - RectF position = mGeckoViewport.getViewport(); - mRootLayer.setPositionAndResolution(RectUtils.round(position), mGeckoViewport.getZoomFactor()); - } - } - RectF getDisplayPort() { return mDisplayPort; } /* Informs Gecko that the screen size has changed. */ private void sendResizeEventIfNecessary(boolean force) { DisplayMetrics metrics = new DisplayMetrics(); GeckoApp.mAppContext.getWindowManager().getDefaultDisplay().getMetrics(metrics); @@ -262,27 +234,33 @@ public class GeckoLayerClient implements private void adjustViewport() { ViewportMetrics viewportMetrics = new ViewportMetrics(mLayerController.getViewportMetrics()); viewportMetrics.setViewport(viewportMetrics.getClampedViewport()); mDisplayPort = calculateDisplayPort(mLayerController.getViewportMetrics()); GeckoAppShell.sendEventToGecko(GeckoEvent.createViewportEvent(viewportMetrics, mDisplayPort)); + mGeckoViewport = viewportMetrics; } /** Implementation of GeckoEventResponder/GeckoEventListener. */ public void handleMessage(String event, JSONObject message) { try { if ("Viewport:Update".equals(event)) { - ViewportMetrics newMetrics = new ViewportMetrics(message); + final ViewportMetrics newMetrics = new ViewportMetrics(message); synchronized (mLayerController) { // keep the old viewport size, but update everything else ImmutableViewportMetrics oldMetrics = mLayerController.getViewportMetrics(); newMetrics.setSize(oldMetrics.getSize()); + mLayerController.post(new Runnable() { + public void run() { + mGeckoViewport = newMetrics; + } + }); mLayerController.setViewportMetrics(newMetrics); mLayerController.abortPanZoomAnimation(); mDisplayPort = calculateDisplayPort(mLayerController.getViewportMetrics()); mReturnDisplayPort = mDisplayPort; } } else if ("Viewport:CalculateDisplayPort".equals(event)) { ImmutableViewportMetrics newMetrics = new ImmutableViewportMetrics(new ViewportMetrics(message)); mReturnDisplayPort = calculateDisplayPort(newMetrics); @@ -319,21 +297,26 @@ public class GeckoLayerClient implements void geometryChanged() { /* Let Gecko know if the screensize has changed */ sendResizeEventIfNecessary(false); if (mLayerController.getRedrawHint()) adjustViewport(); } + /* + * This function returns the last viewport that we sent to Gecko. If any additional events are + * being sent to Gecko that are relative on the Gecko viewport position, they must (a) be relative + * to this viewport, and (b) be sent on the UI thread to avoid races. As long as these two + * conditions are satisfied, and the events being sent to Gecko are processed in FIFO order, the + * events will properly be relative to the Gecko viewport position. Note that if Gecko updates + * its viewport independently, we get notified synchronously and also update this on the UI thread. + */ public ViewportMetrics getGeckoViewportMetrics() { - // Return a copy, as we modify this inside the Gecko thread - if (mGeckoViewport != null) - return new ViewportMetrics(mGeckoViewport); - return null; + return mGeckoViewport; } /** This function is invoked by Gecko via JNI; be careful when modifying signature. * The compositor invokes this function just before compositing a frame where the document * is different from the document composited on the last frame. In these cases, the viewport * information we have in Java is no longer valid and needs to be replaced with the new * viewport information provided. setPageSize will never be invoked on the same frame that * this function is invoked on; and this function will always be called prior to syncViewportInfo. @@ -396,18 +379,17 @@ public class GeckoLayerClient implements // metrics can change between here and there, as it's accessed outside // of the compositor thread. mFrameMetrics = mLayerController.getViewportMetrics(); mCurrentViewTransform.x = mFrameMetrics.viewportRectLeft; mCurrentViewTransform.y = mFrameMetrics.viewportRectTop; mCurrentViewTransform.scale = mFrameMetrics.zoomFactor; - mGeckoDisplayPort.set(x, y, x + width, y + height); - mRootLayer.setDisplayPort(mGeckoDisplayPort); + mRootLayer.setPositionAndResolution(x, y, x + width, y + height, resolution); if (layersUpdated && mDrawListener != null) { /* Used by robocop for testing purposes */ mDrawListener.drawFinished(); } return mCurrentViewTransform; }
--- a/mobile/android/base/gfx/Layer.java +++ b/mobile/android/base/gfx/Layer.java @@ -47,21 +47,19 @@ import java.nio.FloatBuffer; import java.util.concurrent.locks.ReentrantLock; import org.mozilla.gecko.FloatUtils; public abstract class Layer { private final ReentrantLock mTransactionLock; private boolean mInTransaction; private Rect mNewPosition; private float mNewResolution; - private Rect mNewDisplayPort; protected Rect mPosition; protected float mResolution; - protected Rect mDisplayPort; public Layer() { this(null); } public Layer(IntSize size) { mTransactionLock = new ReentrantLock(); if (size == null) { @@ -97,32 +95,22 @@ public abstract class Layer { public abstract void draw(RenderContext context); /** Given the intrinsic size of the layer, returns the pixel boundaries of the layer rect. */ protected RectF getBounds(RenderContext context) { return RectUtils.scale(new RectF(mPosition), context.zoomFactor / mResolution); } /** - * Returns the pixel boundaries of the layer's display-port rect. If no display port - * is set, returns the bounds of the layer. - */ - protected RectF getDisplayPortBounds(RenderContext context) { - if (mDisplayPort != null) - return RectUtils.scale(new RectF(mDisplayPort), context.zoomFactor / mResolution); - return getBounds(context); - } - - /** * Returns the region of the layer that is considered valid. The default - * implementation of this will return the display-port bounds of the layer, - * but this may be overridden. + * implementation of this will return the bounds of the layer, but this + * may be overridden. */ public Region getValidRegion(RenderContext context) { - return new Region(RectUtils.round(getDisplayPortBounds(context))); + return new Region(RectUtils.round(getBounds(context))); } /** * Call this before modifying the layer. Note that, for TileLayers, "modifying the layer" * includes altering the underlying CairoImage in any way. Thus you must call this function * before modifying the byte buffer associated with this layer. * * This function may block, so you should never call this on the main UI thread. @@ -172,46 +160,26 @@ public abstract class Layer { * Only valid inside a transaction. */ public void setResolution(float newResolution) { if (!mInTransaction) throw new RuntimeException("setResolution() is only valid inside a transaction"); mNewResolution = newResolution; } /** - * Returns the layer's display port, or null if none is set. This is the - * rectangle that represents the area the layer will render, which may be - * different to its position. - */ - public Rect getDisplayPort() { - return mDisplayPort; - } - - /** Sets the layer's display port. */ - public void setDisplayPort(Rect newDisplayPort) { - if (!mInTransaction) - throw new RuntimeException("setDisplayPort() is only valid inside a transaction"); - mNewDisplayPort = newDisplayPort; - } - - /** * Subclasses may override this method to perform custom layer updates. This will be called * with the transaction lock held. Subclass implementations of this method must call the * superclass implementation. Returns false if there is still work to be done after this * update is complete. */ protected boolean performUpdates(RenderContext context) { if (mNewPosition != null) { mPosition = mNewPosition; mNewPosition = null; } - if (mNewDisplayPort != null) { - mDisplayPort = mNewDisplayPort; - mNewDisplayPort = null; - } if (mNewResolution != 0.0f) { mResolution = mNewResolution; mNewResolution = 0.0f; } return true; }
--- a/mobile/android/base/gfx/LayerController.java +++ b/mobile/android/base/gfx/LayerController.java @@ -347,38 +347,36 @@ public class LayerController implements RectF displayPort = (mLayerClient == null ? new RectF() : mLayerClient.getDisplayPort()); return !displayPort.contains(adjustedViewport); } /** * Converts a point from layer view coordinates to layer coordinates. In other words, given a * point measured in pixels from the top left corner of the layer view, returns the point in - * pixels measured from the top left corner of the root layer, in the coordinate system of the - * layer itself (CSS pixels). This method is used as part of the process of translating touch - * events to Gecko's coordinate system. + * pixels measured from the last scroll position we sent to Gecko, in CSS pixels. Assuming the + * events being sent to Gecko are processed in FIFO order, this calculation should always be + * correct. */ public PointF convertViewPointToLayerPoint(PointF viewPoint) { - if (mRootLayer == null) - return null; - ImmutableViewportMetrics viewportMetrics = mViewportMetrics; PointF origin = viewportMetrics.getOrigin(); float zoom = viewportMetrics.zoomFactor; - Rect rootPosition = mRootLayer.getPosition(); - float rootScale = mRootLayer.getResolution(); + ViewportMetrics geckoViewport = mLayerClient.getGeckoViewportMetrics(); + PointF geckoOrigin = geckoViewport.getOrigin(); + float geckoZoom = geckoViewport.getZoomFactor(); // viewPoint + origin gives the coordinate in device pixels from the top-left corner of the page. // Divided by zoom, this gives us the coordinate in CSS pixels from the top-left corner of the page. - // rootPosition / rootScale is where Gecko thinks it is (scrollTo position) in CSS pixels from + // geckoOrigin / geckoZoom is where Gecko thinks it is (scrollTo position) in CSS pixels from // the top-left corner of the page. Subtracting the two gives us the offset of the viewPoint from // the current Gecko coordinate in CSS pixels. PointF layerPoint = new PointF( - ((viewPoint.x + origin.x) / zoom) - (rootPosition.left / rootScale), - ((viewPoint.y + origin.y) / zoom) - (rootPosition.top / rootScale)); + ((viewPoint.x + origin.x) / zoom) - (geckoOrigin.x / geckoZoom), + ((viewPoint.y + origin.y) / zoom) - (geckoOrigin.y / geckoZoom)); return layerPoint; } /* * Gesture detection. This is handled only at a high level in this class; we dispatch to the * pan/zoom controller to do the dirty work. */
--- a/mobile/android/base/gfx/LayerRenderer.java +++ b/mobile/android/base/gfx/LayerRenderer.java @@ -575,17 +575,17 @@ public class LayerRenderer implements GL pageRect.height()); if (!untransformedPageRect.contains(mView.getController().getViewport())) mShadowLayer.draw(mPageContext); /* Find the area the root layer will render into, to mask the scissor rect */ Rect rootMask = null; Layer rootLayer = mView.getController().getRoot(); if (rootLayer != null) { - RectF rootBounds = rootLayer.getDisplayPortBounds(mPageContext); + RectF rootBounds = rootLayer.getBounds(mPageContext); rootBounds.offset(-mPageContext.viewport.left, -mPageContext.viewport.top); rootMask = new Rect(); rootBounds.roundOut(rootMask); } /* Draw the checkerboard. */ setScissorRect(); mCheckerboardLayer.setMask(rootMask);
--- a/mobile/android/base/gfx/VirtualLayer.java +++ b/mobile/android/base/gfx/VirtualLayer.java @@ -45,39 +45,27 @@ public class VirtualLayer extends Layer super(size); } @Override public void draw(RenderContext context) { // No-op. } - void setPositionAndResolution(Rect newPosition, float newResolution) { + void setPositionAndResolution(int left, int top, int right, int bottom, float newResolution) { // This is an optimized version of the following code: // beginTransaction(); // try { - // setPosition(newPosition); + // setPosition(new Rect(left, top, right, bottom)); // setResolution(newResolution); // performUpdates(null); // } finally { // endTransaction(); // } // it is safe to drop the transaction lock in this instance (i.e. for the // VirtualLayer that is just a shadow of what gecko is painting) because - // the position and resolution of this layer are never used for anything - // meaningful. - // XXX The above is not true any more; the compositor uses these values - // in order to determine where to draw the checkerboard. The values are - // also used in LayerController's convertViewPointToLayerPoint function. - mPosition = newPosition; + // the position and resolution of this layer are always touched on the compositor + // thread, and therefore do not require synchronization. + mPosition.set(left, top, right, bottom); mResolution = newResolution; } - - @Override - public void setDisplayPort(Rect displayPort) { - // Similar to the above, this removes the lock from setDisplayPort. As - // this is currently only called by the Compositor, and it is only - // accessed by the composition thread, it is safe to remove the locks - // from this call. - mDisplayPort = displayPort; - } }
--- a/widget/android/AndroidJavaWrappers.cpp +++ b/widget/android/AndroidJavaWrappers.cpp @@ -88,18 +88,16 @@ jmethodID AndroidLocation::jGetLatitudeM jmethodID AndroidLocation::jGetLongitudeMethod = 0; jmethodID AndroidLocation::jGetAltitudeMethod = 0; jmethodID AndroidLocation::jGetAccuracyMethod = 0; jmethodID AndroidLocation::jGetBearingMethod = 0; jmethodID AndroidLocation::jGetSpeedMethod = 0; jmethodID AndroidLocation::jGetTimeMethod = 0; jclass AndroidGeckoLayerClient::jGeckoLayerClientClass = 0; -jmethodID AndroidGeckoLayerClient::jBeginDrawingMethod = 0; -jmethodID AndroidGeckoLayerClient::jEndDrawingMethod = 0; jmethodID AndroidGeckoLayerClient::jSetFirstPaintViewport = 0; jmethodID AndroidGeckoLayerClient::jSetPageSize = 0; jmethodID AndroidGeckoLayerClient::jSyncViewportInfoMethod = 0; jmethodID AndroidGeckoLayerClient::jCreateFrameMethod = 0; jmethodID AndroidGeckoLayerClient::jActivateProgramMethod = 0; jmethodID AndroidGeckoLayerClient::jDeactivateProgramMethod = 0; jclass AndroidLayerRendererFrame::jLayerRendererFrameClass = 0; @@ -265,18 +263,16 @@ AndroidRect::InitRectClass(JNIEnv *jEnv) void AndroidGeckoLayerClient::InitGeckoLayerClientClass(JNIEnv *jEnv) { #ifdef MOZ_JAVA_COMPOSITOR initInit(); jGeckoLayerClientClass = getClassGlobalRef("org/mozilla/gecko/gfx/GeckoLayerClient"); - jBeginDrawingMethod = getMethod("beginDrawing", "(IILjava/lang/String;)Z"); - jEndDrawingMethod = getMethod("endDrawing", "()V"); jSetFirstPaintViewport = getMethod("setFirstPaintViewport", "(FFFFF)V"); jSetPageSize = getMethod("setPageSize", "(FFF)V"); jSyncViewportInfoMethod = getMethod("syncViewportInfo", "(IIIIFZ)Lorg/mozilla/gecko/gfx/ViewTransform;"); jCreateFrameMethod = getMethod("createFrame", "()Lorg/mozilla/gecko/gfx/LayerRenderer$Frame;"); jActivateProgramMethod = getMethod("activateProgram", "()V"); jDeactivateProgramMethod = getMethod("deactivateProgram", "()V"); #endif @@ -651,42 +647,16 @@ AndroidGeckoSurfaceView::Draw2D(jobject { JNIEnv *env = AndroidBridge::GetJNIEnv(); if (!env) return; env->CallVoidMethod(wrapped_obj, jDraw2DBufferMethod, buffer, stride); } -bool -AndroidGeckoLayerClient::BeginDrawing(int aWidth, int aHeight, const nsAString &aMetadata) -{ - NS_ASSERTION(!isNull(), "BeginDrawing() called on null layer client!"); - JNIEnv *env = AndroidBridge::GetJNIEnv(); - if (!env) - return false; - - AndroidBridge::AutoLocalJNIFrame jniFrame(env); - jstring jMetadata = env->NewString(nsPromiseFlatString(aMetadata).get(), aMetadata.Length()); - - return env->CallBooleanMethod(wrapped_obj, jBeginDrawingMethod, aWidth, aHeight, jMetadata); -} - -void -AndroidGeckoLayerClient::EndDrawing() -{ - NS_ASSERTION(!isNull(), "EndDrawing() called on null layer client!"); - JNIEnv *env = AndroidBridge::GetJNIEnv(); - if (!env) - return; - - AndroidBridge::AutoLocalJNIFrame jniFrame(env); - return env->CallVoidMethod(wrapped_obj, jEndDrawingMethod); -} - void AndroidGeckoLayerClient::SetFirstPaintViewport(float aOffsetX, float aOffsetY, float aZoom, float aPageWidth, float aPageHeight) { NS_ASSERTION(!isNull(), "SetFirstPaintViewport called on null layer client!"); JNIEnv *env = GetJNIForThread(); // this is called on the compositor thread if (!env) return;
--- a/widget/android/AndroidJavaWrappers.h +++ b/widget/android/AndroidJavaWrappers.h @@ -197,30 +197,26 @@ class AndroidGeckoLayerClient : public W public: static void InitGeckoLayerClientClass(JNIEnv *jEnv); void Init(jobject jobj); AndroidGeckoLayerClient() {} AndroidGeckoLayerClient(jobject jobj) { Init(jobj); } - bool BeginDrawing(int aWidth, int aHeight, const nsAString &aMetadata); - void EndDrawing(); void SetFirstPaintViewport(float aOffsetX, float aOffsetY, float aZoom, float aPageWidth, float aPageHeight); void SetPageSize(float aZoom, float aPageWidth, float aPageHeight); void SyncViewportInfo(const nsIntRect& aDisplayPort, float aDisplayResolution, bool aLayersUpdated, nsIntPoint& aScrollOffset, float& aScaleX, float& aScaleY); void CreateFrame(AndroidLayerRendererFrame& aFrame); void ActivateProgram(); void DeactivateProgram(); protected: static jclass jGeckoLayerClientClass; - static jmethodID jBeginDrawingMethod; - static jmethodID jEndDrawingMethod; static jmethodID jSetFirstPaintViewport; static jmethodID jSetPageSize; static jmethodID jSyncViewportInfoMethod; static jmethodID jCreateFrameMethod; static jmethodID jActivateProgramMethod; static jmethodID jDeactivateProgramMethod; };
--- a/widget/android/nsWindow.cpp +++ b/widget/android/nsWindow.cpp @@ -1153,50 +1153,31 @@ nsWindow::OnDraw(AndroidGeckoEvent *ae) if (metadataProvider) { metadataProvider->PaintingSuppressed(&paintingSuppressed); } if (paintingSuppressed) { return; } layers::renderTraceEventEnd("Check supress", "424242"); - layers::renderTraceEventStart("Get Drawable", "424343"); - nsAutoString metadata; - if (metadataProvider) { - metadataProvider->GetDrawMetadata(metadata); - } - layers::renderTraceEventEnd("Get Drawable", "424343"); - layers::renderTraceEventStart("Get surface", "424545"); static unsigned char bits2[32 * 32 * 2]; nsRefPtr<gfxImageSurface> targetSurface = new gfxImageSurface(bits2, gfxIntSize(32, 32), 32 * 2, gfxASurface::ImageFormatRGB16_565); layers::renderTraceEventEnd("Get surface", "424545"); - layers::renderTraceEventStart("Check Bridge", "434444"); + layers::renderTraceEventStart("Widget draw to", "434646"); nsIntRect dirtyRect = ae->Rect().Intersect(nsIntRect(0, 0, gAndroidBounds.width, gAndroidBounds.height)); - - AndroidGeckoLayerClient &client = AndroidBridge::Bridge()->GetLayerClient(); - if (!client.BeginDrawing(gAndroidBounds.width, gAndroidBounds.height, metadata)) { - return; - } - layers::renderTraceEventEnd("Check Bridge", "434444"); - - layers::renderTraceEventStart("Widget draw to", "434646"); if (targetSurface->CairoStatus()) { ALOG("### Failed to create a valid surface from the bitmap"); } else { DrawTo(targetSurface, dirtyRect); } layers::renderTraceEventEnd("Widget draw to", "434646"); - - layers::renderTraceEventStart("Widget end draw", "434747"); - client.EndDrawing(); - layers::renderTraceEventEnd("Widget end draw", "434747"); return; #endif if (!sSurfaceExists) { return; } AndroidGeckoSurfaceView& sview(AndroidBridge::Bridge()->SurfaceView());