void RootFrameViewport::setScrollOffset(const DoublePoint& offset, ScrollType scrollType)
{
    // Make sure we use the scroll positions as reported by each viewport's ScrollAnimator, since its
    // ScrollableArea's position may have the fractional part truncated off.
    DoublePoint oldPosition = scrollOffsetFromScrollAnimators();

    DoubleSize delta = offset - oldPosition;

    if (delta.isZero())
        return;

    ScrollableArea& primary = !m_invertScrollOrder ? layoutViewport() : visualViewport();
    ScrollableArea& secondary = !m_invertScrollOrder ? visualViewport() : layoutViewport();

    DoublePoint targetPosition = primary.clampScrollPosition(primary.scrollAnimator()->currentPosition() + delta);
    primary.setScrollPosition(targetPosition, scrollType);

    DoubleSize applied = scrollOffsetFromScrollAnimators() - oldPosition;
    delta -= applied;

    if (delta.isZero())
        return;

    targetPosition = secondary.clampScrollPosition(secondary.scrollAnimator()->currentPosition() + delta);
    secondary.setScrollPosition(targetPosition, scrollType);
}
void RootFrameViewport::distributeScrollBetweenViewports(const DoublePoint& offset, ScrollType scrollType, ScrollBehavior behavior)
{
    // Make sure we use the scroll positions as reported by each viewport's ScrollAnimatorBase, since its
    // ScrollableArea's position may have the fractional part truncated off.
    DoublePoint oldPosition = scrollOffsetFromScrollAnimators();

    DoubleSize delta = offset - oldPosition;

    if (delta.isZero())
        return;

    DoublePoint targetPosition = visualViewport().clampScrollPosition(
        visualViewport().scrollAnimator().currentPosition() + delta);

    visualViewport().setScrollPosition(targetPosition, scrollType, behavior);

    // Scroll the secondary viewport if all of the scroll was not applied to the
    // primary viewport.
    DoublePoint updatedPosition = layoutViewport().scrollAnimator().currentPosition() + FloatPoint(targetPosition);
    DoubleSize applied = updatedPosition - oldPosition;
    delta -= applied;

    if (delta.isZero())
        return;

    targetPosition = layoutViewport().clampScrollPosition(layoutViewport().scrollAnimator().currentPosition() + delta);
    layoutViewport().setScrollPosition(targetPosition, scrollType, behavior);
}
예제 #3
0
LayoutRect RootFrameViewport::scrollIntoView(const LayoutRect& rectInContent,
                                             const ScrollAlignment& alignX,
                                             const ScrollAlignment& alignY,
                                             ScrollType scrollType) {
  // We want to move the rect into the viewport that excludes the scrollbars so
  // we intersect the visual viewport with the scrollbar-excluded frameView
  // content rect. However, we don't use visibleContentRect directly since it
  // floors the scroll offset. Instead, we use ScrollAnimatorBase::currentOffset
  // and construct a LayoutRect from that.
  LayoutRect frameRectInContent =
      LayoutRect(FloatPoint(layoutViewport().scrollAnimator().currentOffset()),
                 FloatSize(layoutViewport().visibleContentRect().size()));
  LayoutRect visualRectInContent =
      LayoutRect(FloatPoint(scrollOffsetFromScrollAnimators()),
                 FloatSize(visualViewport().visibleContentRect().size()));

  // Intersect layout and visual rects to exclude the scrollbar from the view
  // rect.
  LayoutRect viewRectInContent =
      intersection(visualRectInContent, frameRectInContent);
  LayoutRect targetViewport = ScrollAlignment::getRectToExpose(
      viewRectInContent, rectInContent, alignX, alignY);
  if (targetViewport != viewRectInContent) {
    setScrollOffset(ScrollOffset(targetViewport.x(), targetViewport.y()),
                    scrollType);
  }

  // RootFrameViewport only changes the viewport relative to the document so we
  // can't change the input rect's location relative to the document origin.
  return rectInContent;
}
LayoutRect RootFrameViewport::scrollIntoView(const LayoutRect& rectInContent, const ScrollAlignment& alignX, const ScrollAlignment& alignY)
{
    // We want to move the rect into the viewport that excludes the scrollbars so we intersect
    // the visual viewport with the scrollbar-excluded frameView content rect. However, we don't
    // use visibleContentRect directly since it floors the scroll position. Instead, we use
    // FrameView::scrollPositionDouble and construct a LayoutRect from that (the FrameView size
    // is always integer sized.

    LayoutRect frameRectInContent = LayoutRect(
        layoutViewport().scrollPositionDouble(),
        layoutViewport().visibleContentRect().size());
    LayoutRect visualRectInContent = LayoutRect(
        layoutViewport().scrollPositionDouble() + toDoubleSize(visualViewport().scrollPositionDouble()),
        visualViewport().visibleContentRect().size());

    LayoutRect viewRectInContent = intersection(visualRectInContent, frameRectInContent);
    LayoutRect targetViewport =
        ScrollAlignment::getRectToExpose(viewRectInContent, rectInContent, alignX, alignY);

    // visualViewport.scrollIntoView will attempt to center the given rect within the viewport
    // so to prevent it from adjusting r's coordinates the rect must match the viewport's size
    // i.e. add the subtracted scrollbars from above back in.
    // FIXME: This is hacky and required because getRectToExpose doesn't naturally account
    // for the two viewports. crbug.com/449340.
    targetViewport.setSize(LayoutSize(visualViewport().visibleContentRect().size()));

    // Snap the visible rect to layout units to match the calculated target viewport rect.
    FloatRect visible =
        LayoutRect(visualViewport().scrollPositionDouble(), visualViewport().visibleContentRect().size());

    float centeringOffsetX = (visible.width() - targetViewport.width()) / 2;
    float centeringOffsetY = (visible.height() - targetViewport.height()) / 2;

    DoublePoint targetOffset(
        targetViewport.x() - centeringOffsetX,
        targetViewport.y() - centeringOffsetY);

    setScrollPosition(targetOffset, ProgrammaticScroll);

    // RootFrameViewport only changes the viewport relative to the document so we can't change the input
    // rect's location relative to the document origin.
    return rectInContent;
}
예제 #5
0
void RootFrameViewport::distributeScrollBetweenViewports(
    const ScrollOffset& offset,
    ScrollType scrollType,
    ScrollBehavior behavior,
    ViewportToScrollFirst scrollFirst) {
  // Make sure we use the scroll offsets as reported by each viewport's
  // ScrollAnimatorBase, since its ScrollableArea's offset may have the
  // fractional part truncated off.
  // TODO(szager): Now that scroll offsets are stored as floats, can we take the
  // scroll offset directly from the ScrollableArea's rather than the animators?
  ScrollOffset oldOffset = scrollOffsetFromScrollAnimators();

  ScrollOffset delta = offset - oldOffset;

  if (delta.isZero())
    return;

  ScrollableArea& primary =
      scrollFirst == VisualViewport ? visualViewport() : layoutViewport();
  ScrollableArea& secondary =
      scrollFirst == VisualViewport ? layoutViewport() : visualViewport();

  ScrollOffset targetOffset = primary.clampScrollOffset(
      primary.scrollAnimator().currentOffset() + delta);

  primary.setScrollOffset(targetOffset, scrollType, behavior);

  // Scroll the secondary viewport if all of the scroll was not applied to the
  // primary viewport.
  ScrollOffset updatedOffset =
      secondary.scrollAnimator().currentOffset() + FloatSize(targetOffset);
  ScrollOffset applied = updatedOffset - oldOffset;
  delta -= applied;

  if (delta.isZero())
    return;

  targetOffset = secondary.clampScrollOffset(
      secondary.scrollAnimator().currentOffset() + delta);
  secondary.setScrollOffset(targetOffset, scrollType, behavior);
}
예제 #6
0
void RootFrameViewport::restoreToAnchor(const ScrollOffset& targetOffset) {
  // Clamp the scroll offset of each viewport now so that we force any invalid
  // offsets to become valid so we can compute the correct deltas.
  visualViewport().setScrollOffset(visualViewport().getScrollOffset(),
                                   ProgrammaticScroll);
  layoutViewport().setScrollOffset(layoutViewport().getScrollOffset(),
                                   ProgrammaticScroll);

  ScrollOffset delta = targetOffset - getScrollOffset();

  visualViewport().setScrollOffset(visualViewport().getScrollOffset() + delta,
                                   ProgrammaticScroll);

  delta = targetOffset - getScrollOffset();

  // Since the main thread FrameView has integer scroll offsets, scroll it to
  // the next pixel and then we'll scroll the visual viewport again to
  // compensate for the sub-pixel offset. We need this "overscroll" to ensure
  // the pixel of which we want to be partially in appears fully inside the
  // FrameView since the VisualViewport is bounded by the FrameView.
  IntSize layoutDelta = IntSize(
      delta.width() < 0 ? floor(delta.width()) : ceil(delta.width()),
      delta.height() < 0 ? floor(delta.height()) : ceil(delta.height()));

  layoutViewport().setScrollOffset(
      ScrollOffset(layoutViewport().scrollOffsetInt() + layoutDelta),
      ProgrammaticScroll);

  delta = targetOffset - getScrollOffset();
  visualViewport().setScrollOffset(visualViewport().getScrollOffset() + delta,
                                   ProgrammaticScroll);
}
ScrollResult RootFrameViewport::handleWheel(const PlatformWheelEvent& event)
{
    updateScrollAnimator();

    ScrollableArea& primary = !m_invertScrollOrder ? layoutViewport() : visualViewport();
    ScrollableArea& secondary = !m_invertScrollOrder ? visualViewport() : layoutViewport();

    ScrollResult viewScrollResult = primary.handleWheel(event);

    // The visual viewport will only accept pixel scrolls.
    if (!event.canScroll() || event.granularity() == ScrollByPageWheelEvent)
        return viewScrollResult;

    // TODO(sataya.m) : The delta in PlatformWheelEvent is negative when scrolling the
    // wheel towards the user, so negate it to get the scroll delta that should be applied
    // to the page. unusedScrollDelta computed in the ScrollResult is also negative. Say
    // there is WheelEvent({0, -10} and page scroll by 2px and unusedScrollDelta computed
    // is {0, -8}. Due to which we have to negate the unusedScrollDelta to obtain the expected
    // animation.Please address http://crbug.com/504389.
    DoublePoint oldOffset = secondary.scrollPositionDouble();
    DoublePoint locationDelta;
    if (viewScrollResult.didScroll()) {
        locationDelta = -DoublePoint(viewScrollResult.unusedScrollDeltaX, viewScrollResult.unusedScrollDeltaY);
    } else {
        if (event.railsMode() != PlatformEvent::RailsModeVertical)
            locationDelta.setX(-event.deltaX());
        if (event.railsMode() != PlatformEvent::RailsModeHorizontal)
            locationDelta.setY(-event.deltaY());
    }

    DoublePoint targetPosition = secondary.clampScrollPosition(
        secondary.scrollPositionDouble() + toDoubleSize(locationDelta));
    secondary.setScrollPosition(targetPosition, UserScroll);

    DoublePoint usedLocationDelta(secondary.scrollPositionDouble() - oldOffset);

    bool didScrollX = viewScrollResult.didScrollX || usedLocationDelta.x();
    bool didScrollY = viewScrollResult.didScrollY || usedLocationDelta.y();
    return ScrollResult(didScrollX, didScrollY, -viewScrollResult.unusedScrollDeltaX - usedLocationDelta.x(), -viewScrollResult.unusedScrollDeltaY - usedLocationDelta.y());
}
ScrollResultOneDimensional RootFrameViewport::userScroll(ScrollDirectionPhysical direction, ScrollGranularity granularity, float delta)
{
    updateScrollAnimator();

    ScrollbarOrientation orientation;

    if (direction == ScrollUp || direction == ScrollDown)
        orientation = VerticalScrollbar;
    else
        orientation = HorizontalScrollbar;

    if (layoutViewport().userInputScrollable(orientation) && visualViewport().userInputScrollable(orientation))
        return ScrollableArea::userScroll(direction, granularity, delta);

    if (visualViewport().userInputScrollable(orientation))
        return visualViewport().userScroll(direction, granularity, delta);

    if (layoutViewport().userInputScrollable(orientation))
        return layoutViewport().userScroll(direction, granularity, delta);

    return ScrollResultOneDimensional(false, delta);
}
예제 #9
0
void RootFrameViewport::updateCompositorScrollAnimations() {
  ScrollableArea::updateCompositorScrollAnimations();
  layoutViewport().updateCompositorScrollAnimations();
  visualViewport().updateCompositorScrollAnimations();
}
예제 #10
0
void RootFrameViewport::serviceScrollAnimations(double monotonicTime) {
  ScrollableArea::serviceScrollAnimations(monotonicTime);
  layoutViewport().serviceScrollAnimations(monotonicTime);
  visualViewport().serviceScrollAnimations(monotonicTime);
}
예제 #11
0
ScrollResult RootFrameViewport::userScroll(ScrollGranularity granularity,
                                           const FloatSize& delta) {
  // TODO(bokan/ymalik): Once smooth scrolling is permanently enabled we
  // should be able to remove this method override and use the base class
  // version: ScrollableArea::userScroll.

  updateScrollAnimator();

  // Distribute the scroll between the visual and layout viewport.

  float stepX = scrollStep(granularity, HorizontalScrollbar);
  float stepY = scrollStep(granularity, VerticalScrollbar);

  FloatSize pixelDelta(delta);
  pixelDelta.scale(stepX, stepY);

  // Precompute the amount of possible scrolling since, when animated,
  // ScrollAnimator::userScroll will report having consumed the total given
  // scroll delta, regardless of how much will actually scroll, but we need to
  // know how much to leave for the layout viewport.
  FloatSize visualConsumedDelta =
      visualViewport().scrollAnimator().computeDeltaToConsume(pixelDelta);

  // Split the remaining delta between scrollable and unscrollable axes of the
  // layout viewport. We only pass a delta to the scrollable axes and remember
  // how much was held back so we can add it to the unused delta in the
  // result.
  FloatSize layoutDelta = pixelDelta - visualConsumedDelta;
  FloatSize scrollableAxisDelta(
      layoutViewport().userInputScrollable(HorizontalScrollbar)
          ? layoutDelta.width()
          : 0,
      layoutViewport().userInputScrollable(VerticalScrollbar)
          ? layoutDelta.height()
          : 0);

  // If there won't be any scrolling, bail early so we don't produce any side
  // effects like cancelling existing animations.
  if (visualConsumedDelta.isZero() && scrollableAxisDelta.isZero()) {
    return ScrollResult(false, false, pixelDelta.width(), pixelDelta.height());
  }

  cancelProgrammaticScrollAnimation();

  // TODO(bokan): Why do we call userScroll on the animators directly and
  // not through the ScrollableAreas?
  ScrollResult visualResult = visualViewport().scrollAnimator().userScroll(
      granularity, visualConsumedDelta);

  if (visualConsumedDelta == pixelDelta)
    return visualResult;

  ScrollResult layoutResult = layoutViewport().scrollAnimator().userScroll(
      granularity, scrollableAxisDelta);

  // Remember to add any delta not used because of !userInputScrollable to the
  // unusedScrollDelta in the result.
  FloatSize unscrollableAxisDelta = layoutDelta - scrollableAxisDelta;

  return ScrollResult(
      visualResult.didScrollX || layoutResult.didScrollX,
      visualResult.didScrollY || layoutResult.didScrollY,
      layoutResult.unusedScrollDeltaX + unscrollableAxisDelta.width(),
      layoutResult.unusedScrollDeltaY + unscrollableAxisDelta.height());
}
예제 #12
0
bool RootFrameViewport::userInputScrollable(
    ScrollbarOrientation orientation) const {
  return visualViewport().userInputScrollable(orientation) ||
         layoutViewport().userInputScrollable(orientation);
}
예제 #13
0
ScrollOffset RootFrameViewport::maximumScrollOffset() const {
  return layoutViewport().maximumScrollOffset() +
         visualViewport().maximumScrollOffset();
}
예제 #14
0
IntSize RootFrameViewport::minimumScrollOffsetInt() const {
  return IntSize(layoutViewport().minimumScrollOffsetInt() +
                 visualViewport().minimumScrollOffsetInt());
}
예제 #15
0
void RootFrameViewport::clearScrollableArea() {
  ScrollableArea::clearScrollableArea();
  layoutViewport().clearScrollableArea();
  visualViewport().clearScrollableArea();
}
예제 #16
0
DoublePoint RootFrameViewport::maximumScrollPositionDouble() const
{
    return layoutViewport().maximumScrollPositionDouble() + toDoubleSize(visualViewport().maximumScrollPositionDouble());
}
예제 #17
0
IntRect RootFrameViewport::visibleContentRect(
    IncludeScrollbarsInRect scrollbarInclusion) const {
  return IntRect(
      IntPoint(scrollOffsetInt()),
      visualViewport().visibleContentRect(scrollbarInclusion).size());
}
예제 #18
0
ScrollOffset RootFrameViewport::scrollOffsetFromScrollAnimators() const {
  return visualViewport().scrollAnimator().currentOffset() +
         layoutViewport().scrollAnimator().currentOffset();
}
예제 #19
0
DoubleRect RootFrameViewport::visibleContentRectDouble(IncludeScrollbarsInRect scrollbarInclusion) const
{
    return DoubleRect(scrollPositionDouble(), visualViewport().visibleContentRectDouble(scrollbarInclusion).size());
}
예제 #20
0
void RootFrameViewport::cancelProgrammaticScrollAnimation() {
  ScrollableArea::cancelProgrammaticScrollAnimation();
  layoutViewport().cancelProgrammaticScrollAnimation();
  visualViewport().cancelProgrammaticScrollAnimation();
}
예제 #21
0
IntPoint RootFrameViewport::maximumScrollPosition() const
{
    return layoutViewport().maximumScrollPosition() + visualViewport().maximumScrollPosition();
}
예제 #22
0
Widget* RootFrameViewport::getWidget() {
  return visualViewport().getWidget();
}
예제 #23
0
DoublePoint RootFrameViewport::scrollOffsetFromScrollAnimators() const
{
    return visualViewport().scrollAnimator()->currentPosition() + layoutViewport().scrollAnimator()->currentPosition();
}
예제 #24
0
ScrollOffset RootFrameViewport::getScrollOffset() const {
  return layoutViewport().getScrollOffset() +
         visualViewport().getScrollOffset();
}
예제 #25
0
IntPoint RootFrameViewport::minimumScrollPosition() const
{
    return IntPoint(layoutViewport().minimumScrollPosition() - visualViewport().minimumScrollPosition());
}