Esempio n. 1
0
void
APZCCallbackHelper::UpdateRootFrame(nsIDOMWindowUtils* aUtils,
                                    FrameMetrics& aMetrics)
{
  // Precondition checks
  MOZ_ASSERT(aUtils);
  MOZ_ASSERT(aMetrics.GetUseDisplayPortMargins());
  if (aMetrics.GetScrollId() == FrameMetrics::NULL_SCROLL_ID) {
    return;
  }

  // Set the scroll port size, which determines the scroll range. For example if
  // a 500-pixel document is shown in a 100-pixel frame, the scroll port length would
  // be 100, and gecko would limit the maximum scroll offset to 400 (so as to prevent
  // overscroll). Note that if the content here was zoomed to 2x, the document would
  // be 1000 pixels long but the frame would still be 100 pixels, and so the maximum
  // scroll range would be 900. Therefore this calculation depends on the zoom applied
  // to the content relative to the container.
  // Note that this needs to happen before scrolling the frame (in UpdateFrameCommon),
  // otherwise the scroll position may get clamped incorrectly.
  CSSSize scrollPort = aMetrics.CalculateCompositedSizeInCssPixels();
  aUtils->SetScrollPositionClampingScrollPortSize(scrollPort.width, scrollPort.height);

  nsIContent* content = nsLayoutUtils::FindContentFor(aMetrics.GetScrollId());
  ScrollFrame(content, aMetrics);

  // The pres shell resolution is updated by the the async zoom since the
  // last paint.
  float presShellResolution = aMetrics.GetPresShellResolution()
                            * aMetrics.GetAsyncZoom().scale;
  aUtils->SetResolutionAndScaleTo(presShellResolution, presShellResolution);

  SetDisplayPortMargins(aUtils, content, aMetrics);
}
void
APZCCallbackHelper::UpdateRootFrame(FrameMetrics& aMetrics)
{
  if (aMetrics.GetScrollId() == FrameMetrics::NULL_SCROLL_ID) {
    return;
  }
  nsIContent* content = nsLayoutUtils::FindContentFor(aMetrics.GetScrollId());
  if (!content) {
    return;
  }

  nsCOMPtr<nsIPresShell> shell = GetPresShell(content);
  if (!shell || aMetrics.GetPresShellId() != shell->GetPresShellId()) {
    return;
  }

  MOZ_ASSERT(aMetrics.GetUseDisplayPortMargins());

  if (gfxPrefs::APZAllowZooming()) {
    // If zooming is disabled then we don't really want to let APZ fiddle
    // with these things. In theory setting the resolution here should be a
    // no-op, but setting the SPCSPS is bad because it can cause a stale value
    // to be returned by window.innerWidth/innerHeight (see bug 1187792).

    float presShellResolution = nsLayoutUtils::GetResolution(shell);

    // If the pres shell resolution has changed on the content side side
    // the time this repaint request was fired, consider this request out of date
    // and drop it; setting a zoom based on the out-of-date resolution can have
    // the effect of getting us stuck with the stale resolution.
    if (presShellResolution != aMetrics.GetPresShellResolution()) {
      return;
    }

    // Set the scroll port size, which determines the scroll range. For example if
    // a 500-pixel document is shown in a 100-pixel frame, the scroll port length would
    // be 100, and gecko would limit the maximum scroll offset to 400 (so as to prevent
    // overscroll). Note that if the content here was zoomed to 2x, the document would
    // be 1000 pixels long but the frame would still be 100 pixels, and so the maximum
    // scroll range would be 900. Therefore this calculation depends on the zoom applied
    // to the content relative to the container.
    // Note that this needs to happen before scrolling the frame (in UpdateFrameCommon),
    // otherwise the scroll position may get clamped incorrectly.
    CSSSize scrollPort = aMetrics.CalculateCompositedSizeInCssPixels();
    nsLayoutUtils::SetScrollPositionClampingScrollPortSize(shell, scrollPort);

    // The pres shell resolution is updated by the the async zoom since the
    // last paint.
    presShellResolution = aMetrics.GetPresShellResolution()
                        * aMetrics.GetAsyncZoom().scale;
    nsLayoutUtils::SetResolutionAndScaleTo(shell, presShellResolution);
  }

  // Do this as late as possible since scrolling can flush layout. It also
  // adjusts the display port margins, so do it before we set those.
  ScrollFrame(content, aMetrics);

  SetDisplayPortMargins(shell, content, aMetrics);
}
void
APZCCallbackHelper::UpdateRootFrame(nsIPresShell* aPresShell,
                                    FrameMetrics& aMetrics)
{
  // Precondition checks
  MOZ_ASSERT(aPresShell);
  MOZ_ASSERT(aMetrics.GetUseDisplayPortMargins());
  if (aMetrics.GetScrollId() == FrameMetrics::NULL_SCROLL_ID) {
    return;
  }

  float presShellResolution = nsLayoutUtils::GetResolution(aPresShell);

  // If the pres shell resolution has changed on the content side side
  // the time this repaint request was fired, consider this request out of date
  // and drop it; setting a zoom based on the out-of-date resolution can have
  // the effect of getting us stuck with the stale resolution.
  if (presShellResolution != aMetrics.GetPresShellResolution()) {
    return;
  }

  // Set the scroll port size, which determines the scroll range. For example if
  // a 500-pixel document is shown in a 100-pixel frame, the scroll port length would
  // be 100, and gecko would limit the maximum scroll offset to 400 (so as to prevent
  // overscroll). Note that if the content here was zoomed to 2x, the document would
  // be 1000 pixels long but the frame would still be 100 pixels, and so the maximum
  // scroll range would be 900. Therefore this calculation depends on the zoom applied
  // to the content relative to the container.
  // Note that this needs to happen before scrolling the frame (in UpdateFrameCommon),
  // otherwise the scroll position may get clamped incorrectly.
  CSSSize scrollPort = aMetrics.CalculateCompositedSizeInCssPixels();
  nsLayoutUtils::SetScrollPositionClampingScrollPortSize(aPresShell, scrollPort);

  // The pres shell resolution is updated by the the async zoom since the
  // last paint.
  presShellResolution = aMetrics.GetPresShellResolution()
                      * aMetrics.GetAsyncZoom().scale;
  nsLayoutUtils::SetResolutionAndScaleTo(aPresShell, presShellResolution);

  // Do this as late as possible since scrolling can flush layout. It also
  // adjusts the display port margins, so do it before we set those.
  nsIContent* content = nsLayoutUtils::FindContentFor(aMetrics.GetScrollId());
  ScrollFrame(content, aMetrics);

  SetDisplayPortMargins(aPresShell, content, aMetrics);
}
CSSRect
CalculateRectToZoomTo(const nsCOMPtr<nsIDocument>& aRootContentDocument,
                      const CSSPoint& aPoint)
{
  // Ensure the layout information we get is up-to-date.
  aRootContentDocument->FlushPendingNotifications(FlushType::Layout);

  // An empty rect as return value is interpreted as "zoom out".
  const CSSRect zoomOut;

  nsCOMPtr<nsIPresShell> shell = aRootContentDocument->GetShell();
  if (!shell) {
    return zoomOut;
  }

  nsIScrollableFrame* rootScrollFrame = shell->GetRootScrollFrameAsScrollable();
  if (!rootScrollFrame) {
    return zoomOut;
  }

  nsCOMPtr<dom::Element> element = ElementFromPoint(shell, aPoint);
  if (!element) {
    return zoomOut;
  }

  while (element && !ShouldZoomToElement(element)) {
    element = element->GetParentElement();
  }

  if (!element) {
    return zoomOut;
  }

  FrameMetrics metrics = nsLayoutUtils::CalculateBasicFrameMetrics(rootScrollFrame);
  CSSRect compositedArea(metrics.GetScrollOffset(), metrics.CalculateCompositedSizeInCssPixels());
  const CSSCoord margin = 15;
  CSSRect rect = nsLayoutUtils::GetBoundingContentRect(element, rootScrollFrame);

  // If the element is taller than the visible area of the page scale
  // the height of the |rect| so that it has the same aspect ratio as
  // the root frame.  The clipped |rect| is centered on the y value of
  // the touch point. This allows tall narrow elements to be zoomed.
  if (!rect.IsEmpty() && compositedArea.width > 0.0f) {
    const float widthRatio = rect.width / compositedArea.width;
    float targetHeight = compositedArea.height * widthRatio;
    if (widthRatio < 0.9 && targetHeight < rect.height) {
      const CSSPoint scrollPoint = CSSPoint::FromAppUnits(rootScrollFrame->GetScrollPosition());
      float newY = aPoint.y + scrollPoint.y - (targetHeight * 0.5f);
      if ((newY + targetHeight) > (rect.y + rect.height)) {
        rect.y += rect.height - targetHeight;
      } else if (newY > rect.y) {
        rect.y = newY;
      }
      rect.height = targetHeight;
    }
  }

  rect = CSSRect(std::max(metrics.GetScrollableRect().x, rect.x - margin),
                 rect.y,
                 rect.width + 2 * margin,
                 rect.height);
  // Constrict the rect to the screen's right edge
  rect.width = std::min(rect.width, metrics.GetScrollableRect().XMost() - rect.x);

  // If the rect is already taking up most of the visible area and is
  // stretching the width of the page, then we want to zoom out instead.
  if (IsRectZoomedIn(rect, compositedArea)) {
    return zoomOut;
  }

  CSSRect rounded(rect);
  rounded.Round();

  // If the block we're zooming to is really tall, and the user double-tapped
  // more than a screenful of height from the top of it, then adjust the
  // y-coordinate so that we center the actual point the user double-tapped
  // upon. This prevents flying to the top of the page when double-tapping
  // to zoom in (bug 761721). The 1.2 multiplier is just a little fuzz to
  // compensate for 'rect' including horizontal margins but not vertical ones.
  CSSCoord cssTapY = metrics.GetScrollOffset().y + aPoint.y;
  if ((rect.height > rounded.height) && (cssTapY > rounded.y + (rounded.height * 1.2))) {
    rounded.y = cssTapY - (rounded.height / 2);
  }

  return rounded;
}
Esempio n. 5
0
void
APZCCallbackHelper::UpdateRootFrame(nsIDOMWindowUtils* aUtils,
                                    FrameMetrics& aMetrics)
{
    // Precondition checks
    MOZ_ASSERT(aUtils);
    MOZ_ASSERT(aMetrics.GetUseDisplayPortMargins());
    if (aMetrics.GetScrollId() == FrameMetrics::NULL_SCROLL_ID) {
        return;
    }

    // Set the scroll port size, which determines the scroll range. For example if
    // a 500-pixel document is shown in a 100-pixel frame, the scroll port length would
    // be 100, and gecko would limit the maximum scroll offset to 400 (so as to prevent
    // overscroll). Note that if the content here was zoomed to 2x, the document would
    // be 1000 pixels long but the frame would still be 100 pixels, and so the maximum
    // scroll range would be 900. Therefore this calculation depends on the zoom applied
    // to the content relative to the container.
    CSSSize scrollPort = aMetrics.CalculateCompositedSizeInCssPixels();
    aUtils->SetScrollPositionClampingScrollPortSize(scrollPort.width, scrollPort.height);

    // Scroll the window to the desired spot
    nsIScrollableFrame* sf = nsLayoutUtils::FindScrollableFrameFor(aMetrics.GetScrollId());
    bool scrollUpdated = false;
    CSSPoint actualScrollOffset = ScrollFrameTo(sf, aMetrics.GetScrollOffset(), scrollUpdated);

    if (scrollUpdated) {
        // Correct the display port due to the difference between mScrollOffset and the
        // actual scroll offset.
        AdjustDisplayPortForScrollDelta(aMetrics, actualScrollOffset);
    } else {
        // For whatever reason we couldn't update the scroll offset on the scroll frame,
        // which means the data APZ used for its displayport calculation is stale. Fall
        // back to a sane default behaviour. Note that we don't tile-align the recentered
        // displayport because tile-alignment depends on the scroll position, and the
        // scroll position here is out of our control. See bug 966507 comment 21 for a
        // more detailed explanation.
        RecenterDisplayPort(aMetrics);
    }

    aMetrics.SetScrollOffset(actualScrollOffset);

    // The mZoom variable on the frame metrics stores the CSS-to-screen scale for this
    // frame. This scale includes all of the (cumulative) resolutions set on the presShells
    // from the root down to this frame. However, when setting the resolution, we only
    // want the piece of the resolution that corresponds to this presShell, rather than
    // all of the cumulative stuff, so we need to divide out the parent resolutions.
    // Finally, we multiply by a ScreenToLayerScale of 1.0f because the goal here is to
    // take the async zoom calculated by the APZC and tell gecko about it (turning it into
    // a "sync" zoom) which will update the resolution at which the layer is painted.
    ParentLayerToLayerScale presShellResolution =
        aMetrics.GetZoom()
        / aMetrics.mDevPixelsPerCSSPixel
        / aMetrics.GetParentResolution()
        * ScreenToLayerScale(1.0f);
    aUtils->SetResolution(presShellResolution.scale, presShellResolution.scale);

    // Finally, we set the displayport.
    nsCOMPtr<nsIContent> content = nsLayoutUtils::FindContentFor(aMetrics.GetScrollId());
    if (!content) {
        return;
    }
    nsCOMPtr<nsIDOMElement> element = do_QueryInterface(content);
    if (!element) {
        return;
    }

    gfx::IntSize alignment = gfxPrefs::LayersTilesEnabled()
        ? gfx::IntSize(gfxPrefs::LayersTileWidth(), gfxPrefs::LayersTileHeight()) :
          gfx::IntSize(0, 0);
    LayerMargin margins = aMetrics.GetDisplayPortMargins();
    aUtils->SetDisplayPortMarginsForElement(margins.left,
                                            margins.top,
                                            margins.right,
                                            margins.bottom,
                                            alignment.width,
                                            alignment.height,
                                            element, 0);
    CSSRect baseCSS = aMetrics.CalculateCompositedRectInCssPixels();
    nsRect base(baseCSS.x * nsPresContext::AppUnitsPerCSSPixel(),
                baseCSS.y * nsPresContext::AppUnitsPerCSSPixel(),
                baseCSS.width * nsPresContext::AppUnitsPerCSSPixel(),
                baseCSS.height * nsPresContext::AppUnitsPerCSSPixel());
    nsLayoutUtils::SetDisplayPortBaseIfNotSet(content, base);
}
Esempio n. 6
0
CSSRect
CalculateRectToZoomTo(const nsCOMPtr<nsIDocument>& aRootContentDocument,
                      const CSSPoint& aPoint)
{
  // Ensure the layout information we get is up-to-date.
  aRootContentDocument->FlushPendingNotifications(Flush_Layout);

  // An empty rect as return value is interpreted as "zoom out".
  const CSSRect zoomOut;

  nsCOMPtr<nsIPresShell> shell = aRootContentDocument->GetShell();
  if (!shell) {
    return zoomOut;
  }

  nsIScrollableFrame* rootScrollFrame = shell->GetRootScrollFrameAsScrollable();
  if (!rootScrollFrame) {
    return zoomOut;
  }

  nsCOMPtr<dom::Element> element = ElementFromPoint(shell, aPoint);
  if (!element) {
    return zoomOut;
  }

  while (element && !ShouldZoomToElement(element)) {
    element = element->GetParentElement();
  }

  if (!element) {
    return zoomOut;
  }

  FrameMetrics metrics = nsLayoutUtils::CalculateBasicFrameMetrics(rootScrollFrame);
  CSSRect compositedArea(metrics.GetScrollOffset(), metrics.CalculateCompositedSizeInCssPixels());
  const CSSCoord margin = 15;
  CSSRect rect = GetBoundingContentRect(shell, element, rootScrollFrame);
  rect = CSSRect(std::max(metrics.GetScrollableRect().x, rect.x - margin),
                 rect.y,
                 rect.width + 2 * margin,
                 rect.height);
  // Constrict the rect to the screen's right edge
  rect.width = std::min(rect.width, metrics.GetScrollableRect().XMost() - rect.x);

  // If the rect is already taking up most of the visible area and is
  // stretching the width of the page, then we want to zoom out instead.
  if (IsRectZoomedIn(rect, compositedArea)) {
    return zoomOut;
  }

  CSSRect rounded(rect);
  rounded.Round();

  // If the block we're zooming to is really tall, and the user double-tapped
  // more than a screenful of height from the top of it, then adjust the
  // y-coordinate so that we center the actual point the user double-tapped
  // upon. This prevents flying to the top of the page when double-tapping
  // to zoom in (bug 761721). The 1.2 multiplier is just a little fuzz to
  // compensate for 'rect' including horizontal margins but not vertical ones.
  CSSCoord cssTapY = metrics.GetScrollOffset().y + aPoint.y;
  if ((rect.height > rounded.height) && (cssTapY > rounded.y + (rounded.height * 1.2))) {
    rounded.y = cssTapY - (rounded.height / 2);
  }

  return rounded;
}
Esempio n. 7
0
void
APZCCallbackHelper::UpdateRootFrame(nsIDOMWindowUtils* aUtils,
                                    FrameMetrics& aMetrics)
{
    // Precondition checks
    MOZ_ASSERT(aUtils);
    MOZ_ASSERT(aMetrics.GetUseDisplayPortMargins());
    if (aMetrics.GetScrollId() == FrameMetrics::NULL_SCROLL_ID) {
        return;
    }

    // Set the scroll port size, which determines the scroll range. For example if
    // a 500-pixel document is shown in a 100-pixel frame, the scroll port length would
    // be 100, and gecko would limit the maximum scroll offset to 400 (so as to prevent
    // overscroll). Note that if the content here was zoomed to 2x, the document would
    // be 1000 pixels long but the frame would still be 100 pixels, and so the maximum
    // scroll range would be 900. Therefore this calculation depends on the zoom applied
    // to the content relative to the container.
    CSSSize scrollPort = aMetrics.CalculateCompositedSizeInCssPixels();
    aUtils->SetScrollPositionClampingScrollPortSize(scrollPort.width, scrollPort.height);

    // Scroll the window to the desired spot
    nsIScrollableFrame* sf = nsLayoutUtils::FindScrollableFrameFor(aMetrics.GetScrollId());
    bool scrollUpdated = false;
    CSSPoint actualScrollOffset = ScrollFrameTo(sf, aMetrics.GetScrollOffset(), scrollUpdated);

    if (scrollUpdated) {
        // Correct the display port due to the difference between mScrollOffset and the
        // actual scroll offset.
        AdjustDisplayPortForScrollDelta(aMetrics, actualScrollOffset);
    } else {
        // For whatever reason we couldn't update the scroll offset on the scroll frame,
        // which means the data APZ used for its displayport calculation is stale. Fall
        // back to a sane default behaviour. Note that we don't tile-align the recentered
        // displayport because tile-alignment depends on the scroll position, and the
        // scroll position here is out of our control. See bug 966507 comment 21 for a
        // more detailed explanation.
        RecenterDisplayPort(aMetrics);
    }

    aMetrics.SetScrollOffset(actualScrollOffset);

    // The pres shell resolution is updated by the the async zoom since the
    // last paint.
    float presShellResolution = aMetrics.GetPresShellResolution()
                              * aMetrics.GetAsyncZoom().scale;
    aUtils->SetResolutionAndScaleTo(presShellResolution, presShellResolution);

    // Finally, we set the displayport.
    nsCOMPtr<nsIContent> content = nsLayoutUtils::FindContentFor(aMetrics.GetScrollId());
    if (!content) {
        return;
    }
    nsCOMPtr<nsIDOMElement> element = do_QueryInterface(content);
    if (!element) {
        return;
    }

    ScreenMargin margins = aMetrics.GetDisplayPortMargins();
    aUtils->SetDisplayPortMarginsForElement(margins.left,
                                            margins.top,
                                            margins.right,
                                            margins.bottom,
                                            element, 0);
    CSSRect baseCSS = aMetrics.CalculateCompositedRectInCssPixels();
    nsRect base(0, 0,
                baseCSS.width * nsPresContext::AppUnitsPerCSSPixel(),
                baseCSS.height * nsPresContext::AppUnitsPerCSSPixel());
    nsLayoutUtils::SetDisplayPortBaseIfNotSet(content, base);
}