bool AsyncPanZoomController::SampleContentTransformForFrame(const TimeStamp& aSampleTime, const FrameMetrics& aFrame, const gfx3DMatrix& aCurrentTransform, gfx3DMatrix* aNewTransform) { // 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 // smooth. If an animation frame is requested, it is the compositor's // responsibility to schedule a composite. bool requestAnimationFrame = false; // Scales on the root layer, on what's currently painted. float rootScaleX = aCurrentTransform.GetXScale(), rootScaleY = aCurrentTransform.GetYScale(); nsIntPoint metricsScrollOffset(0, 0); nsIntPoint scrollOffset; float localScaleX, localScaleY; { MonitorAutoLock mon(mMonitor); // If a fling is currently happening, apply it now. We can pull the updated // metrics afterwards. requestAnimationFrame = requestAnimationFrame || DoFling(aSampleTime - mLastSampleTime); // Current local transform; this is not what's painted but rather what PZC has // transformed due to touches like panning or pinching. Eventually, the root // layer transform will become this during runtime, but we must wait for Gecko // to repaint. localScaleX = mFrameMetrics.mResolution.width; localScaleY = mFrameMetrics.mResolution.height; if (aFrame.IsScrollable()) { metricsScrollOffset = aFrame.mViewportScrollOffset; } scrollOffset = mFrameMetrics.mViewportScrollOffset; } nsIntPoint scrollCompensation( (scrollOffset.x / rootScaleX - metricsScrollOffset.x) * localScaleX, (scrollOffset.y / rootScaleY - metricsScrollOffset.y) * localScaleY); ViewTransform treeTransform(-scrollCompensation, localScaleX, localScaleY); *aNewTransform = gfx3DMatrix(treeTransform) * aCurrentTransform; mLastSampleTime = aSampleTime; return requestAnimationFrame; }
void AsyncPanZoomController::GetContentTransformForFrame(const FrameMetrics& aFrame, const gfx3DMatrix& aRootTransform, const gfxSize& aWidgetSize, gfx3DMatrix* aTreeTransform, gfxPoint* aReverseViewTranslation) { // Scales on the root layer, on what's currently painted. float rootScaleX = aRootTransform.GetXScale(), rootScaleY = aRootTransform.GetYScale(); // Current local transform; this is not what's painted but rather what PZC has // transformed due to touches like panning or pinching. Eventually, the root // layer transform will become this during runtime, but we must wait for Gecko // to repaint. float localScaleX = mFrameMetrics.mResolution.width, localScaleY = mFrameMetrics.mResolution.height; // Handle transformations for asynchronous panning and zooming. We determine the // zoom used by Gecko from the transformation set on the root layer, and we // determine the scroll offset used by Gecko from the frame metrics of the // primary scrollable layer. We compare this to the desired zoom and scroll // offset in the view transform we obtained from Java in order to compute the // transformation we need to apply. float tempScaleDiffX = rootScaleX * localScaleX; float tempScaleDiffY = rootScaleY * localScaleY; nsIntPoint metricsScrollOffset(0, 0); if (aFrame.IsScrollable()) metricsScrollOffset = aFrame.mViewportScrollOffset; nsIntPoint scrollCompensation( mFrameMetrics.mViewportScrollOffset.x / rootScaleX - metricsScrollOffset.x, mFrameMetrics.mViewportScrollOffset.y / rootScaleY - metricsScrollOffset.y); ViewTransform treeTransform(-scrollCompensation, localScaleX, localScaleY); *aTreeTransform = gfx3DMatrix(treeTransform); float offsetX = mFrameMetrics.mViewportScrollOffset.x / tempScaleDiffX, offsetY = mFrameMetrics.mViewportScrollOffset.y / tempScaleDiffY; nsIntRect localContentRect = mFrameMetrics.mContentRect; offsetX = NS_MAX((float)localContentRect.x, NS_MIN(offsetX, (float)(localContentRect.XMost() - aWidgetSize.width))); offsetY = NS_MAX((float)localContentRect.y, NS_MIN(offsetY, (float)(localContentRect.YMost() - aWidgetSize.height))); *aReverseViewTranslation = gfxPoint(offsetX - metricsScrollOffset.x, offsetY - metricsScrollOffset.y); }
// Compute the transform of the shadow tree contained by // |aContainerFrame| to widget space. We transform because the // subprocess layer manager renders to a different top-left than where // the shadow tree is drawn here and because a scale can be set on the // shadow tree. static ViewTransform ComputeShadowTreeTransform(nsIFrame* aContainerFrame, nsFrameLoader* aRootFrameLoader, const FrameMetrics* aMetrics, const ViewConfig& aConfig, float aTempScaleX = 1.0, float aTempScaleY = 1.0) { // |aMetrics->mViewportScrollOffset| The frame's scroll offset when it was // painted, in content document pixels. // |aConfig.mScrollOffset| What our user expects, or wants, the // frame scroll offset to be in chrome // document app units. // // So we set a compensating translation that moves the content document // pixels to where the user wants them to be. // nscoord auPerDevPixel = aContainerFrame->PresContext()->AppUnitsPerDevPixel(); nsIntPoint scrollOffset = aConfig.mScrollOffset.ToNearestPixels(auPerDevPixel); // metricsScrollOffset is in layer coordinates. nsIntPoint metricsScrollOffset = aMetrics->mViewportScrollOffset; if (aRootFrameLoader->AsyncScrollEnabled() && !aMetrics->mDisplayPort.IsEmpty()) { // Only use asynchronous scrolling if it is enabled and there is a // displayport defined. It is useful to have a scroll layer that is // synchronously scrolled for identifying a scroll area before it is // being actively scrolled. nsIntPoint scrollCompensation( (scrollOffset.x / aTempScaleX - metricsScrollOffset.x) * aConfig.mXScale, (scrollOffset.y / aTempScaleY - metricsScrollOffset.y) * aConfig.mYScale); return ViewTransform(-scrollCompensation, aConfig.mXScale, aConfig.mYScale); } else { return ViewTransform(nsIntPoint(0, 0), 1, 1); } }
void CompositorParent::TransformShadowTree() { Layer* layer = GetPrimaryScrollableLayer(); ShadowLayer* shadow = layer->AsShadowLayer(); ContainerLayer* container = layer->AsContainerLayer(); const FrameMetrics* metrics = &container->GetFrameMetrics(); const gfx3DMatrix& rootTransform = mLayerManager->GetRoot()->GetTransform(); const gfx3DMatrix& currentTransform = layer->GetTransform(); float rootScaleX = rootTransform.GetXScale(); float rootScaleY = rootTransform.GetYScale(); if (mIsFirstPaint && metrics) { nsIntPoint scrollOffset = metrics->mViewportScrollOffset; mContentSize = metrics->mContentSize; SetFirstPaintViewport(scrollOffset.x, scrollOffset.y, 1/rootScaleX, mContentSize.width, mContentSize.height, metrics->mCSSContentSize.width, metrics->mCSSContentSize.height); mIsFirstPaint = false; } else if (metrics && (metrics->mContentSize != mContentSize)) { mContentSize = metrics->mContentSize; SetPageSize(1/rootScaleX, mContentSize.width, mContentSize.height, metrics->mCSSContentSize.width, metrics->mCSSContentSize.height); } // We synchronise the viewport information with Java after sending the above // notifications, so that Java can take these into account in its response. if (metrics) { // Calculate the absolute display port to send to Java nsIntRect displayPort = metrics->mDisplayPort; nsIntPoint scrollOffset = metrics->mViewportScrollOffset; displayPort.x += scrollOffset.x; displayPort.y += scrollOffset.y; SyncViewportInfo(displayPort, 1/rootScaleX, mLayersUpdated, mScrollOffset, mXScale, mYScale); mLayersUpdated = false; } // Handle transformations for asynchronous panning and zooming. We determine the // zoom used by Gecko from the transformation set on the root layer, and we // determine the scroll offset used by Gecko from the frame metrics of the // primary scrollable layer. We compare this to the desired zoom and scroll // offset in the view transform we obtained from Java in order to compute the // transformation we need to apply. if (metrics) { float tempScaleDiffX = rootScaleX * mXScale; float tempScaleDiffY = rootScaleY * mYScale; nsIntPoint metricsScrollOffset(0, 0); if (metrics->IsScrollable()) metricsScrollOffset = metrics->mViewportScrollOffset; nsIntPoint scrollCompensation( (mScrollOffset.x / tempScaleDiffX - metricsScrollOffset.x) * mXScale, (mScrollOffset.y / tempScaleDiffY - metricsScrollOffset.y) * mYScale); ViewTransform treeTransform(-scrollCompensation, mXScale, mYScale); shadow->SetShadowTransform(gfx3DMatrix(treeTransform) * currentTransform); } else { ViewTransform treeTransform(nsIntPoint(0,0), mXScale, mYScale); shadow->SetShadowTransform(gfx3DMatrix(treeTransform) * currentTransform); } }
void CompositorParent::TransformShadowTree() { Layer* layer = GetPrimaryScrollableLayer(); ShadowLayer* shadow = layer->AsShadowLayer(); ContainerLayer* container = layer->AsContainerLayer(); const FrameMetrics& metrics = container->GetFrameMetrics(); const gfx3DMatrix& rootTransform = mLayerManager->GetRoot()->GetTransform(); const gfx3DMatrix& currentTransform = layer->GetTransform(); float rootScaleX = rootTransform.GetXScale(); float rootScaleY = rootTransform.GetYScale(); if (mIsFirstPaint) { mContentRect = metrics.mContentRect; SetFirstPaintViewport(metrics.mViewportScrollOffset, 1/rootScaleX, mContentRect, metrics.mCSSContentRect); mIsFirstPaint = false; } else if (!metrics.mContentRect.IsEqualEdges(mContentRect)) { mContentRect = metrics.mContentRect; SetPageRect(1/rootScaleX, mContentRect, metrics.mCSSContentRect); } // We synchronise the viewport information with Java after sending the above // notifications, so that Java can take these into account in its response. // Calculate the absolute display port to send to Java nsIntRect displayPort = metrics.mDisplayPort; nsIntPoint scrollOffset = metrics.mViewportScrollOffset; displayPort.x += scrollOffset.x; displayPort.y += scrollOffset.y; SyncViewportInfo(displayPort, 1/rootScaleX, mLayersUpdated, mScrollOffset, mXScale, mYScale); mLayersUpdated = false; // Handle transformations for asynchronous panning and zooming. We determine the // zoom used by Gecko from the transformation set on the root layer, and we // determine the scroll offset used by Gecko from the frame metrics of the // primary scrollable layer. We compare this to the desired zoom and scroll // offset in the view transform we obtained from Java in order to compute the // transformation we need to apply. float tempScaleDiffX = rootScaleX * mXScale; float tempScaleDiffY = rootScaleY * mYScale; nsIntPoint metricsScrollOffset(0, 0); if (metrics.IsScrollable()) metricsScrollOffset = metrics.mViewportScrollOffset; nsIntPoint scrollCompensation( (mScrollOffset.x / tempScaleDiffX - metricsScrollOffset.x) * mXScale, (mScrollOffset.y / tempScaleDiffY - metricsScrollOffset.y) * mYScale); ViewTransform treeTransform(-scrollCompensation, mXScale, mYScale); shadow->SetShadowTransform(gfx3DMatrix(treeTransform) * currentTransform); // Alter the scroll offset so that fixed position layers remain within // the page area. float offsetX = mScrollOffset.x / tempScaleDiffX; float offsetY = mScrollOffset.y / tempScaleDiffY; offsetX = NS_MAX((float)mContentRect.x, NS_MIN(offsetX, (float)(mContentRect.XMost() - mWidgetSize.width))); offsetY = NS_MAX((float)mContentRect.y, NS_MIN(offsetY, (float)(mContentRect.YMost() - mWidgetSize.height))); gfxPoint reverseViewTranslation(offsetX - metricsScrollOffset.x, offsetY - metricsScrollOffset.y); TranslateFixedLayers(layer, reverseViewTranslation); }