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;
}
예제 #3
0
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);
}