bool ClientLayerManager::ProgressiveUpdateCallback(bool aHasPendingNewThebesContent, gfx::Rect& aViewport, float& aScaleX, float& aScaleY, bool aDrawingCritical) { #ifdef MOZ_WIDGET_ANDROID Layer* primaryScrollable = GetPrimaryScrollableLayer(); if (primaryScrollable) { const FrameMetrics& metrics = primaryScrollable->AsContainerLayer()->GetFrameMetrics(); // This is derived from the code in // gfx/layers/ipc/CompositorParent.cpp::TransformShadowTree. const gfx3DMatrix& rootTransform = GetRoot()->GetTransform(); float devPixelRatioX = 1 / rootTransform.GetXScale(); float devPixelRatioY = 1 / rootTransform.GetYScale(); const gfx::Rect& metricsDisplayPort = (aDrawingCritical && !metrics.mCriticalDisplayPort.IsEmpty()) ? metrics.mCriticalDisplayPort : metrics.mDisplayPort; gfx::Rect displayPort((metricsDisplayPort.x + metrics.mScrollOffset.x) * devPixelRatioX, (metricsDisplayPort.y + metrics.mScrollOffset.y) * devPixelRatioY, metricsDisplayPort.width * devPixelRatioX, metricsDisplayPort.height * devPixelRatioY); return AndroidBridge::Bridge()->ProgressiveUpdateCallback( aHasPendingNewThebesContent, displayPort, devPixelRatioX, aDrawingCritical, aViewport, aScaleX, aScaleY); } #endif return false; }
bool AsyncCompositionManager::ApplyAsyncContentTransformToTree(TimeStamp aCurrentFrame, Layer *aLayer, bool* aWantNextFrame) { bool appliedTransform = false; for (Layer* child = aLayer->GetFirstChild(); child; child = child->GetNextSibling()) { appliedTransform |= ApplyAsyncContentTransformToTree(aCurrentFrame, child, aWantNextFrame); } ContainerLayer* container = aLayer->AsContainerLayer(); if (!container) { return appliedTransform; } if (AsyncPanZoomController* controller = container->GetAsyncPanZoomController()) { LayerComposite* layerComposite = aLayer->AsLayerComposite(); gfx3DMatrix oldTransform = aLayer->GetTransform(); ViewTransform treeTransform; ScreenPoint scrollOffset; *aWantNextFrame |= controller->SampleContentTransformForFrame(aCurrentFrame, &treeTransform, scrollOffset); const gfx3DMatrix& rootTransform = mLayerManager->GetRoot()->GetTransform(); const FrameMetrics& metrics = container->GetFrameMetrics(); // XXX We use rootTransform instead of metrics.mResolution here because on // Fennec the resolution is set on the root layer rather than the scrollable layer. // The SyncFrameMetrics call and the paintScale variable are used on Fennec only // so it doesn't affect any other platforms. See bug 732971. CSSToLayerScale paintScale = metrics.mDevPixelsPerCSSPixel / LayerToLayoutDeviceScale(rootTransform.GetXScale(), rootTransform.GetYScale()); CSSRect displayPort(metrics.mCriticalDisplayPort.IsEmpty() ? metrics.mDisplayPort : metrics.mCriticalDisplayPort); LayerMargin fixedLayerMargins(0, 0, 0, 0); ScreenPoint offset(0, 0); SyncFrameMetrics(scrollOffset, treeTransform.mScale.scale, metrics.mScrollableRect, mLayersUpdated, displayPort, paintScale, mIsFirstPaint, fixedLayerMargins, offset); mIsFirstPaint = false; mLayersUpdated = false; // Apply the render offset mLayerManager->GetCompositor()->SetScreenRenderOffset(offset); gfx3DMatrix transform(gfx3DMatrix(treeTransform) * aLayer->GetTransform()); // 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. transform.Scale(1.0f/container->GetPreXScale(), 1.0f/container->GetPreYScale(), 1); transform.ScalePost(1.0f/aLayer->GetPostXScale(), 1.0f/aLayer->GetPostYScale(), 1); layerComposite->SetShadowTransform(transform); 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. #ifdef MOZ_WIDGET_ANDROID // XXX We use rootTransform instead of the resolution on the individual layer's // FrameMetrics on Fennec because the resolution is set on the root layer rather // than the scrollable layer. See bug 732971. On non-Fennec we do the right thing. LayoutDeviceToLayerScale resolution(1.0 / rootTransform.GetXScale(), 1.0 / rootTransform.GetYScale()); #else LayoutDeviceToLayerScale resolution = metrics.mResolution; #endif oldTransform.Scale(resolution.scale, resolution.scale, 1); AlignFixedLayersForAnchorPoint(aLayer, aLayer, oldTransform, fixedLayerMargins); appliedTransform = true; } return appliedTransform; }
const nsIntRect AsyncPanZoomController::CalculatePendingDisplayPort() { float scale = mFrameMetrics.mResolution.width; nsIntRect viewport = mFrameMetrics.mViewport; viewport.ScaleRoundIn(1 / scale); #ifdef USE_LARGER_DISPLAYPORT const float SIZE_MULTIPLIER = 2.0f; nsIntPoint scrollOffset = mFrameMetrics.mViewportScrollOffset; gfx::Rect contentRect = mFrameMetrics.mCSSContentRect; // Paint a larger portion of the screen than just what we can see. This makes // it less likely that we'll checkerboard when panning around and Gecko hasn't // repainted yet. float desiredWidth = viewport.width * SIZE_MULTIPLIER, desiredHeight = viewport.height * SIZE_MULTIPLIER; // The displayport is relative to the current scroll offset. Here's a little // diagram to make it easier to see: // // - - - - // | | // ************* // * | | * // - -*- @------ -*- - // | * |=====| * | // * |=====| * // | * |=====| * | // - -*- ------- -*- - // * | | * // ************* // | | // - - - - // // The full --- area with === inside it is the actual viewport rect, the *** area // is the displayport, and the - - - area is an imaginary additional page on all 4 // borders of the actual page. Notice that the displayport intersects half-way with // each of the imaginary extra pages. The @ symbol at the top left of the // viewport marks the current scroll offset. From the @ symbol to the far left // and far top, it is clear that this distance is 1/4 of the displayport's // height/width dimension. gfx::Rect displayPort(-desiredWidth / 4, -desiredHeight / 4, desiredWidth, desiredHeight); // Check if the desired boundaries go over the CSS page rect along the top or // left. If they do, shift them to the right or down. float oldDisplayPortX = displayPort.x, oldDisplayPortY = displayPort.y; if (displayPort.X() + scrollOffset.x < contentRect.X()) displayPort.x = contentRect.X() - scrollOffset.x; if (displayPort.Y() + scrollOffset.y < contentRect.Y()) displayPort.y = contentRect.Y() - scrollOffset.y; // We don't need to paint the extra area that was going to overlap with the // content rect. Subtract out this extra width or height. displayPort.width -= displayPort.x - oldDisplayPortX; displayPort.height -= displayPort.y - oldDisplayPortY; // Check if the desired boundaries go over the CSS page rect along the right // or bottom. If they do, subtract out some height or width such that they // perfectly align with the end of the CSS page rect. if (displayPort.XMost() + scrollOffset.x > contentRect.XMost()) displayPort.width = NS_MAX(0.0f, contentRect.XMost() - (displayPort.X() + scrollOffset.x)); if (displayPort.YMost() + scrollOffset.y > contentRect.YMost()) displayPort.height = NS_MAX(0.0f, contentRect.YMost() - (displayPort.Y() + scrollOffset.y)); return nsIntRect(NS_lround(displayPort.X()), NS_lround(displayPort.Y()), NS_lround(displayPort.Width()), NS_lround(displayPort.Height())); #else return nsIntRect(0, 0, NS_lround(viewport.Width()), NS_lround(viewport.Height())); #endif }
const nsIntRect AsyncPanZoomController::CalculatePendingDisplayPort() { float scale = mFrameMetrics.mResolution.width; nsIntRect viewport = mFrameMetrics.mViewport; viewport.ScaleRoundIn(1 / scale); nsIntPoint scrollOffset = mFrameMetrics.mViewportScrollOffset; nsPoint velocity = GetVelocityVector(); // The displayport is relative to the current scroll offset. Here's a little // diagram to make it easier to see: // // - - - - // | | // ************* // * | | * // - -*- @------ -*- - // | * |=====| * | // * |=====| * // | * |=====| * | // - -*- ------- -*- - // * | | * // ************* // | | // - - - - // // The full --- area with === inside it is the actual viewport rect, the *** area // is the displayport, and the - - - area is an imaginary additional page on all 4 // borders of the actual page. Notice that the displayport intersects half-way with // each of the imaginary extra pages. The @ symbol at the top left of the // viewport marks the current scroll offset. From the @ symbol to the far left // and far top, it is clear that this distance is 1/4 of the displayport's // height/width dimension. const float STATIONARY_SIZE_MULTIPLIER = 2.0f; const float SKATE_SIZE_MULTIPLIER = 3.0f; gfx::Rect displayPort(0, 0, viewport.width * STATIONARY_SIZE_MULTIPLIER, viewport.height * STATIONARY_SIZE_MULTIPLIER); // Iff there's motion along only one axis of movement, and it's above a // threshold, then we want to paint a larger area in the direction of that // motion so that it's less likely to checkerboard. Also note that the other // axis doesn't need its displayport enlarged beyond the viewport dimension, // since it is impossible for it to checkerboard along that axis until motion // begins on it. if (fabsf(velocity.x) > MIN_SKATE_SPEED && fabsf(velocity.y) < MIN_SKATE_SPEED) { displayPort.height = viewport.height; displayPort.width = viewport.width * SKATE_SIZE_MULTIPLIER; displayPort.x = velocity.x > 0 ? 0 : viewport.width - displayPort.width; } else if (fabsf(velocity.x) < MIN_SKATE_SPEED && fabsf(velocity.y) > MIN_SKATE_SPEED) { displayPort.width = viewport.width; displayPort.height = viewport.height * SKATE_SIZE_MULTIPLIER; displayPort.y = velocity.y > 0 ? 0 : viewport.height - displayPort.height; } else { displayPort.x = -displayPort.width / 4; displayPort.y = -displayPort.height / 4; } gfx::Rect shiftedDisplayPort = displayPort; // Both the scroll offset and displayport are in CSS pixels. We're scaling // the scroll offset because Gecko will internally scale the displayport by // the resolution, so we'll get clipping at the far bottom or far right if we // directly get the intersection of the displayport offset by the scroll // offset and the CSS content rect. shiftedDisplayPort.MoveBy(scrollOffset.x / scale, scrollOffset.y / scale); displayPort = shiftedDisplayPort.Intersect(mFrameMetrics.mCSSContentRect); displayPort.MoveBy(-scrollOffset.x / scale, -scrollOffset.y / scale); // Round the displayport so we don't get any truncation, then get the nsIntRect // from this. displayPort.Round(); return nsIntRect(displayPort.x, displayPort.y, displayPort.width, displayPort.height); }