diff --git a/gfx/layers/ipc/AsyncPanZoomController.cpp b/gfx/layers/ipc/AsyncPanZoomController.cpp index 893fbe8c5c9..3c99253b0e4 100644 --- a/gfx/layers/ipc/AsyncPanZoomController.cpp +++ b/gfx/layers/ipc/AsyncPanZoomController.cpp @@ -1112,7 +1112,8 @@ AsyncPanZoomController::FireAsyncScrollOnTimeout() bool AsyncPanZoomController::SampleContentTransformForFrame(const TimeStamp& aSampleTime, ContainerLayer* aLayer, - ViewTransform* aNewTransform) { + ViewTransform* aNewTransform, + gfxPoint* aScrollOffset) { // The eventual return value of this function. The compositor needs to know // whether or not to advance by a frame as soon as it can. For example, if a // fling is happening, it has to keep compositing so that the animation is @@ -1221,6 +1222,7 @@ bool AsyncPanZoomController::SampleContentTransformForFrame(const TimeStamp& aSa gfxPoint scrollCompensation( (scrollOffset / rootScale - metricsScrollOffset) * localScale); *aNewTransform = ViewTransform(-scrollCompensation, localScale); + *aScrollOffset = scrollOffset * localScale; mLastSampleTime = aSampleTime; diff --git a/gfx/layers/ipc/AsyncPanZoomController.h b/gfx/layers/ipc/AsyncPanZoomController.h index c64610c8b46..5a927f195e1 100644 --- a/gfx/layers/ipc/AsyncPanZoomController.h +++ b/gfx/layers/ipc/AsyncPanZoomController.h @@ -177,7 +177,8 @@ public: */ bool SampleContentTransformForFrame(const TimeStamp& aSampleTime, ContainerLayer* aLayer, - ViewTransform* aTransform); + ViewTransform* aNewTransform, + gfxPoint* aScrollOffset); /** * A shadow layer update has arrived. |aViewportFrame| is the new FrameMetrics diff --git a/gfx/layers/ipc/CompositorParent.cpp b/gfx/layers/ipc/CompositorParent.cpp index 203ca539083..591f750e15d 100644 --- a/gfx/layers/ipc/CompositorParent.cpp +++ b/gfx/layers/ipc/CompositorParent.cpp @@ -846,10 +846,22 @@ CompositorParent::ApplyAsyncContentTransformToTree(TimeStamp aCurrentFrame, LayerComposite* layerComposite = aLayer->AsLayerComposite(); ViewTransform treeTransform; + gfxPoint scrollOffset; *aWantNextFrame |= controller->SampleContentTransformForFrame(aCurrentFrame, container, - &treeTransform); + &treeTransform, + &scrollOffset); + + gfx::Margin fixedLayerMargins(0, 0, 0, 0); + float offsetX = 0, offsetY = 0; + SyncFrameMetrics(aLayer, treeTransform, scrollOffset, fixedLayerMargins, + offsetX, offsetY, mIsFirstPaint, mLayersUpdated); + mIsFirstPaint = false; + mLayersUpdated = false; + + // Apply the render offset + mLayerManager->GetCompositor()->SetScreenRenderOffset(gfx::Point(offsetX, offsetY)); gfx3DMatrix transform(gfx3DMatrix(treeTransform) * aLayer->GetTransform()); // The transform already takes the resolution scale into account. Since we @@ -863,7 +875,6 @@ CompositorParent::ApplyAsyncContentTransformToTree(TimeStamp aCurrentFrame, 1); layerComposite->SetShadowTransform(transform); - gfx::Margin fixedLayerMargins(0, 0, 0, 0); TransformFixedLayers( aLayer, -treeTransform.mTranslation / treeTransform.mScale, diff --git a/gfx/layers/ipc/CompositorParent.h b/gfx/layers/ipc/CompositorParent.h index 1bb4f3cbcd8..75f77e32c34 100644 --- a/gfx/layers/ipc/CompositorParent.h +++ b/gfx/layers/ipc/CompositorParent.h @@ -181,6 +181,12 @@ protected: virtual void SyncViewportInfo(const nsIntRect& aDisplayPort, float aDisplayResolution, bool aLayersUpdated, nsIntPoint& aScrollOffset, float& aScaleX, float& aScaleY, gfx::Margin& aFixedLayerMargins, float& aOffsetX, float& aOffsetY); + virtual void SyncFrameMetrics(Layer* aLayer, const ViewTransform& aTreeTransform, + const gfxPoint& aScrollOffset, gfx::Margin& aFixedLayerMargins, + float& aOffsetX, float& aOffsetY, + bool aIsFirstPaint, bool aLayersUpdated) { + } + void SetEGLSurfaceSize(int width, int height); private: diff --git a/mobile/android/base/gfx/GeckoLayerClient.java b/mobile/android/base/gfx/GeckoLayerClient.java index e2c20dec0ed..7f01f3a98dd 100644 --- a/mobile/android/base/gfx/GeckoLayerClient.java +++ b/mobile/android/base/gfx/GeckoLayerClient.java @@ -657,6 +657,21 @@ public class GeckoLayerClient implements LayerView.Listener, PanZoomTarget return mCurrentViewTransform; } + /* Invoked by JNI from the compositor thread */ + public ViewTransform syncFrameMetrics(float offsetX, float offsetY, float zoom, + float cssPageLeft, float cssPageTop, float cssPageRight, float cssPageBottom, + boolean layersUpdated, int x, int y, int width, int height, float resolution, + boolean isFirstPaint) + { + if (isFirstPaint) { + RectF pageRect = RectUtils.scale(new RectF(cssPageLeft, cssPageTop, cssPageRight, cssPageBottom), zoom); + setFirstPaintViewport(offsetX, offsetY, zoom, pageRect.left, pageRect.top, pageRect.right, + pageRect.bottom, cssPageLeft, cssPageTop, cssPageRight, cssPageBottom); + } + + return syncViewportInfo(x, y, width, height, resolution, layersUpdated); + } + /** This function is invoked by Gecko via JNI; be careful when modifying signature. */ public LayerRenderer.Frame createFrame() { // Create the shaders and textures if necessary. diff --git a/widget/android/AndroidBridge.cpp b/widget/android/AndroidBridge.cpp index 887860edc30..30ae668e6da 100644 --- a/widget/android/AndroidBridge.cpp +++ b/widget/android/AndroidBridge.cpp @@ -2120,6 +2120,19 @@ AndroidBridge::SyncViewportInfo(const nsIntRect& aDisplayPort, float aDisplayRes aOffsetX, aOffsetY); } +void AndroidBridge::SyncFrameMetrics(const gfx::Point& aOffset, float aZoom, const gfx::Rect& aCssPageRect, + bool aLayersUpdated, const gfx::Rect& aDisplayPort, float aDisplayResolution, + bool aIsFirstPaint, gfx::Margin& aFixedLayerMargins, float& aOffsetX, float& aOffsetY) +{ + AndroidGeckoLayerClient *client = mLayerClient; + if (!client) + return; + + client->SyncFrameMetrics(aOffset, aZoom, aCssPageRect, + aLayersUpdated, aDisplayPort, aDisplayResolution, + aIsFirstPaint, aFixedLayerMargins, aOffsetX, aOffsetY); +} + AndroidBridge::AndroidBridge() : mLayerClient(NULL), mNativePanZoomController(NULL) diff --git a/widget/android/AndroidBridge.h b/widget/android/AndroidBridge.h index 65499b413b4..34d5312d84d 100644 --- a/widget/android/AndroidBridge.h +++ b/widget/android/AndroidBridge.h @@ -344,6 +344,9 @@ public: void SyncViewportInfo(const nsIntRect& aDisplayPort, float aDisplayResolution, bool aLayersUpdated, nsIntPoint& aScrollOffset, float& aScaleX, float& aScaleY, gfx::Margin& aFixedLayerMargins, float& aOffsetX, float& aOffsetY); + void SyncFrameMetrics(const gfx::Point& aOffset, float aZoom, const gfx::Rect& aCssPageRect, + bool aLayersUpdated, const gfx::Rect& aDisplayPort, float aDisplayResolution, + bool aIsFirstPaint, gfx::Margin& aFixedLayerMargins, float& aOffsetX, float& aOffsetY); void AddPluginView(jobject view, const gfxRect& rect, bool isFullScreen); void RemovePluginView(jobject view, bool isFullScreen); diff --git a/widget/android/AndroidJavaWrappers.cpp b/widget/android/AndroidJavaWrappers.cpp index 944d68a1228..e5923f58817 100644 --- a/widget/android/AndroidJavaWrappers.cpp +++ b/widget/android/AndroidJavaWrappers.cpp @@ -89,6 +89,7 @@ jclass AndroidGeckoLayerClient::jDisplayportClass = 0; jmethodID AndroidGeckoLayerClient::jSetFirstPaintViewport = 0; jmethodID AndroidGeckoLayerClient::jSetPageRect = 0; jmethodID AndroidGeckoLayerClient::jSyncViewportInfoMethod = 0; +jmethodID AndroidGeckoLayerClient::jSyncFrameMetricsMethod = 0; jmethodID AndroidGeckoLayerClient::jCreateFrameMethod = 0; jmethodID AndroidGeckoLayerClient::jActivateProgramMethod = 0; jmethodID AndroidGeckoLayerClient::jDeactivateProgramMethod = 0; @@ -349,6 +350,8 @@ AndroidGeckoLayerClient::InitGeckoLayerClientClass(JNIEnv *jEnv) jSetPageRect = getMethod("setPageRect", "(FFFF)V"); jSyncViewportInfoMethod = getMethod("syncViewportInfo", "(IIIIFZ)Lorg/mozilla/gecko/gfx/ViewTransform;"); + jSyncFrameMetricsMethod = getMethod("syncFrameMetrics", + "(FFFFFFFZIIIIFZ)Lorg/mozilla/gecko/gfx/ViewTransform;"); jCreateFrameMethod = getMethod("createFrame", "()Lorg/mozilla/gecko/gfx/LayerRenderer$Frame;"); jActivateProgramMethod = getMethod("activateProgram", "()V"); jDeactivateProgramMethod = getMethod("deactivateProgram", "()V"); @@ -911,6 +914,42 @@ AndroidGeckoLayerClient::SyncViewportInfo(const nsIntRect& aDisplayPort, float a aOffsetY = viewTransform.GetOffsetY(env); } +void +AndroidGeckoLayerClient::SyncFrameMetrics(const gfx::Point& aOffset, float aZoom, const gfx::Rect& aCssPageRect, + bool aLayersUpdated, const gfx::Rect& aDisplayPort, float aDisplayResolution, + bool aIsFirstPaint, gfx::Margin& aFixedLayerMargins, float& aOffsetX, float& aOffsetY) +{ + NS_ASSERTION(!isNull(), "SyncFrameMetrics called on null layer client!"); + JNIEnv *env = GetJNIForThread(); // this is called on the compositor thread + if (!env) + return; + + AutoLocalJNIFrame jniFrame(env); + + // convert the displayport rect from scroll-relative CSS pixels to document-relative device pixels + int dpX = NS_lround((aDisplayPort.x * aDisplayResolution) + aOffset.x); + int dpY = NS_lround((aDisplayPort.y * aDisplayResolution) + aOffset.y); + int dpW = NS_lround(aDisplayPort.width * aDisplayResolution); + int dpH = NS_lround(aDisplayPort.height * aDisplayResolution); + + jobject viewTransformJObj = env->CallObjectMethod(wrapped_obj, jSyncFrameMetricsMethod, + aOffset.x, aOffset.y, aZoom, + aCssPageRect.x, aCssPageRect.y, aCssPageRect.XMost(), aCssPageRect.YMost(), + aLayersUpdated, dpX, dpY, dpW, dpH, aDisplayResolution, + aIsFirstPaint); + + if (jniFrame.CheckForException()) + return; + + NS_ABORT_IF_FALSE(viewTransformJObj, "No view transform object!"); + + AndroidViewTransform viewTransform; + viewTransform.Init(viewTransformJObj); + viewTransform.GetFixedLayerMargins(env, aFixedLayerMargins); + aOffsetX = viewTransform.GetOffsetX(env); + aOffsetY = viewTransform.GetOffsetY(env); +} + bool AndroidGeckoLayerClient::ProgressiveUpdateCallback(bool aHasPendingNewThebesContent, const gfx::Rect& aDisplayPort, diff --git a/widget/android/AndroidJavaWrappers.h b/widget/android/AndroidJavaWrappers.h index 699d4b3c94f..079d89df301 100644 --- a/widget/android/AndroidJavaWrappers.h +++ b/widget/android/AndroidJavaWrappers.h @@ -272,6 +272,9 @@ public: void SyncViewportInfo(const nsIntRect& aDisplayPort, float aDisplayResolution, bool aLayersUpdated, nsIntPoint& aScrollOffset, float& aScaleX, float& aScaleY, gfx::Margin& aFixedLayerMargins, float& aOffsetX, float& aOffsetY); + void SyncFrameMetrics(const gfx::Point& aOffset, float aZoom, const gfx::Rect& aCssPageRect, + bool aLayersUpdated, const gfx::Rect& aDisplayPort, float aDisplayResolution, + bool aIsFirstPaint, gfx::Margin& aFixedLayerMargins, float& aOffsetX, float& aOffsetY); bool ProgressiveUpdateCallback(bool aHasPendingNewThebesContent, const gfx::Rect& aDisplayPort, float aDisplayResolution, bool aDrawingCritical, gfx::Rect& aViewport, float& aScaleX, float& aScaleY); bool CreateFrame(AutoLocalJNIFrame *jniFrame, AndroidLayerRendererFrame& aFrame); bool ActivateProgram(AutoLocalJNIFrame *jniFrame); @@ -283,6 +286,7 @@ protected: static jmethodID jSetFirstPaintViewport; static jmethodID jSetPageRect; static jmethodID jSyncViewportInfoMethod; + static jmethodID jSyncFrameMetricsMethod; static jmethodID jCreateFrameMethod; static jmethodID jActivateProgramMethod; static jmethodID jDeactivateProgramMethod; diff --git a/widget/android/nsWindow.cpp b/widget/android/nsWindow.cpp index b0fa71b1085..bebd5fd7313 100644 --- a/widget/android/nsWindow.cpp +++ b/widget/android/nsWindow.cpp @@ -2491,6 +2491,24 @@ public: controller->NotifyLayersUpdated(targetLayer->AsContainerLayer()->GetFrameMetrics(), isFirstPaint); } } + + virtual void SyncFrameMetrics(Layer* aLayer, const ViewTransform& aTreeTransform, + const gfxPoint& aScrollOffset, mozilla::gfx::Margin& aFixedLayerMargins, + float& aOffsetX, float& aOffsetY, + bool aIsFirstPaint, bool aLayersUpdated) MOZ_OVERRIDE + { + const gfx3DMatrix& rootTransform = GetLayerManager()->GetRoot()->GetTransform(); + ContainerLayer* container = aLayer->AsContainerLayer(); + const FrameMetrics& metrics = container->GetFrameMetrics(); + + mozilla::gfx::Rect displayPortLayersPixels(metrics.mCriticalDisplayPort.IsEmpty() ? + metrics.mDisplayPort : metrics.mCriticalDisplayPort); + mozilla::gfx::Point scrollOffset(aScrollOffset.x, aScrollOffset.y); + + AndroidBridge::Bridge()->SyncFrameMetrics(scrollOffset, aTreeTransform.mScale.width, metrics.mScrollableRect, + aLayersUpdated, displayPortLayersPixels, 1 / rootTransform.GetXScale(), + aIsFirstPaint, aFixedLayerMargins, aOffsetX, aOffsetY); + } }; CompositorParent*