void AndroidCompositorWidget::SetFirstPaintViewport(const LayerIntPoint& aOffset, const CSSToLayerScale& aZoom, const CSSRect& aCssPageRect) { auto layerClient = static_cast<nsWindow*>(RealWidget())->GetLayerClient(); if (!layerClient) { return; } layerClient->SetFirstPaintViewport( float(aOffset.x), float(aOffset.y), aZoom.scale, aCssPageRect.x, aCssPageRect.y, aCssPageRect.XMost(), aCssPageRect.YMost()); }
void AsyncCompositionManager::TransformScrollableLayer(Layer* aLayer, const LayoutDeviceToLayerScale& aResolution) { LayerComposite* layerComposite = aLayer->AsLayerComposite(); ContainerLayer* container = aLayer->AsContainerLayer(); const FrameMetrics& metrics = container->GetFrameMetrics(); // We must apply the resolution scale before a pan/zoom transform, so we call // GetTransform here. const gfx3DMatrix& currentTransform = aLayer->GetTransform(); gfx3DMatrix oldTransform = currentTransform; gfx3DMatrix treeTransform; CSSToLayerScale geckoZoom = metrics.mDevPixelsPerCSSPixel * aResolution; LayerIntPoint scrollOffsetLayerPixels = RoundedToInt(metrics.mScrollOffset * geckoZoom); if (mIsFirstPaint) { mContentRect = metrics.mScrollableRect; SetFirstPaintViewport(scrollOffsetLayerPixels, geckoZoom, mContentRect); mIsFirstPaint = false; } else if (!metrics.mScrollableRect.IsEqualEdges(mContentRect)) { mContentRect = metrics.mScrollableRect; SetPageRect(mContentRect); } // 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 LayerIntRect displayPort = RoundedToInt( (metrics.mCriticalDisplayPort.IsEmpty() ? metrics.mDisplayPort : metrics.mCriticalDisplayPort ) * geckoZoom); displayPort += scrollOffsetLayerPixels; LayerMargin fixedLayerMargins(0, 0, 0, 0); ScreenPoint offset(0, 0); // Ideally we would initialize userZoom to AsyncPanZoomController::CalculateResolution(metrics) // but this causes a reftest-ipc test to fail (see bug 883646 comment 27). The reason for this // appears to be that metrics.mZoom is poorly initialized in some scenarios. In these scenarios, // however, we can assume there is no async zooming in progress and so the following statement // works fine. CSSToScreenScale userZoom(metrics.mDevPixelsPerCSSPixel.scale * metrics.mResolution.scale); ScreenPoint userScroll = metrics.mScrollOffset * userZoom; SyncViewportInfo(displayPort, geckoZoom, mLayersUpdated, userScroll, userZoom, fixedLayerMargins, offset); mLayersUpdated = false; // Apply the render offset mLayerManager->GetCompositor()->SetScreenRenderOffset(offset); // 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 user zoom and scroll // offset in the view transform we obtained from Java in order to compute the // transformation we need to apply. LayerToScreenScale zoomAdjust = userZoom / geckoZoom; LayerIntPoint geckoScroll(0, 0); if (metrics.IsScrollable()) { geckoScroll = scrollOffsetLayerPixels; } LayerPoint translation = (userScroll / zoomAdjust) - geckoScroll; treeTransform = gfx3DMatrix(ViewTransform(-translation, userZoom / metrics.mDevPixelsPerCSSPixel)); // The transform already takes the resolution scale into account. Since we // will apply the resolution scale again when computing the effective // transform, we must apply the inverse resolution scale here. gfx3DMatrix computedTransform = treeTransform * currentTransform; computedTransform.Scale(1.0f/container->GetPreXScale(), 1.0f/container->GetPreYScale(), 1); computedTransform.ScalePost(1.0f/container->GetPostXScale(), 1.0f/container->GetPostYScale(), 1); layerComposite->SetShadowTransform(computedTransform); NS_ASSERTION(!layerComposite->GetShadowTransformSetByAnimation(), "overwriting animated transform!"); // Apply resolution scaling to the old transform - the layer tree as it is // doesn't have the necessary transform to display correctly. oldTransform.Scale(aResolution.scale, aResolution.scale, 1); // Make sure that overscroll and under-zoom are represented in the old // transform so that fixed position content moves and scales accordingly. // These calculations will effectively scale and offset fixed position layers // in screen space when the compensatory transform is performed in // AlignFixedLayersForAnchorPoint. ScreenRect contentScreenRect = mContentRect * userZoom; gfxPoint3D overscrollTranslation; if (userScroll.x < contentScreenRect.x) { overscrollTranslation.x = contentScreenRect.x - userScroll.x; } else if (userScroll.x + metrics.mCompositionBounds.width > contentScreenRect.XMost()) { overscrollTranslation.x = contentScreenRect.XMost() - (userScroll.x + metrics.mCompositionBounds.width); } if (userScroll.y < contentScreenRect.y) { overscrollTranslation.y = contentScreenRect.y - userScroll.y; } else if (userScroll.y + metrics.mCompositionBounds.height > contentScreenRect.YMost()) { overscrollTranslation.y = contentScreenRect.YMost() - (userScroll.y + metrics.mCompositionBounds.height); } oldTransform.Translate(overscrollTranslation); gfxSize underZoomScale(1.0f, 1.0f); if (mContentRect.width * userZoom.scale < metrics.mCompositionBounds.width) { underZoomScale.width = (mContentRect.width * userZoom.scale) / metrics.mCompositionBounds.width; } if (mContentRect.height * userZoom.scale < metrics.mCompositionBounds.height) { underZoomScale.height = (mContentRect.height * userZoom.scale) / metrics.mCompositionBounds.height; } oldTransform.Scale(underZoomScale.width, underZoomScale.height, 1); // Make sure fixed position layers don't move away from their anchor points // when we're asynchronously panning or zooming AlignFixedLayersForAnchorPoint(aLayer, aLayer, oldTransform, fixedLayerMargins); }
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); }