void
AndroidCompositorWidget::SyncFrameMetrics(const ParentLayerPoint& aScrollOffset,
                                          const CSSToParentLayerScale& aZoom,
                                          const CSSRect& aCssPageRect,
                                          const CSSRect& aDisplayPort,
                                          const CSSToLayerScale& aPaintedResolution,
                                          bool aLayersUpdated,
                                          int32_t aPaintSyncId,
                                          ScreenMargin& aFixedLayerMargins)
{
    auto layerClient = static_cast<nsWindow*>(RealWidget())->GetLayerClient();
    if (!layerClient) {
        return;
    }

    // convert the displayport rect from document-relative CSS pixels to
    // document-relative device pixels
    LayerIntRect dp = gfx::RoundedToInt(aDisplayPort * aPaintedResolution);

    java::ViewTransform::LocalRef viewTransform = layerClient->SyncFrameMetrics(
            aScrollOffset.x, aScrollOffset.y, aZoom.scale,
            aCssPageRect.x, aCssPageRect.y,
            aCssPageRect.XMost(), aCssPageRect.YMost(),
            dp.x, dp.y, dp.width, dp.height,
            aPaintedResolution.scale, aLayersUpdated, aPaintSyncId);

    MOZ_ASSERT(viewTransform, "No view transform object!");

    aFixedLayerMargins.top = viewTransform->FixedLayerMarginTop();
    aFixedLayerMargins.right = viewTransform->FixedLayerMarginRight();
    aFixedLayerMargins.bottom = viewTransform->FixedLayerMarginBottom();
    aFixedLayerMargins.left = viewTransform->FixedLayerMarginLeft();
}
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;
}