bool VisualViewport::magnifyScaleAroundAnchor(float magnifyDelta, const FloatPoint& anchor)
{
    const float oldPageScale = scale();
    const float newPageScale = frameHost().chromeClient().clampPageScaleFactorToLimits(
        magnifyDelta * oldPageScale);
    if (newPageScale == oldPageScale)
        return false;
    if (!mainFrame() || !mainFrame()->view())
        return false;

    // Keep the center-of-pinch anchor in a stable position over the course
    // of the magnify.
    FloatPoint anchorAtOldScale = anchor.scaledBy(1.f / oldPageScale);
    FloatPoint anchorAtNewScale = anchor.scaledBy(1.f / newPageScale);
    FloatSize anchorDelta = anchorAtOldScale - anchorAtNewScale;

    // First try to use the anchor's delta to scroll the FrameView.
    FloatSize anchorDeltaUnusedByScroll = anchorDelta;

    if (!frameHost().settings().invertViewportScrollOrder()) {
        FrameView* view = mainFrame()->view();
        DoublePoint oldPosition = view->scrollPositionDouble();
        view->scrollBy(DoubleSize(anchorDelta.width(), anchorDelta.height()), UserScroll);
        DoublePoint newPosition = view->scrollPositionDouble();
        anchorDeltaUnusedByScroll -= toFloatSize(newPosition - oldPosition);
    }

    // Manually bubble any remaining anchor delta up to the visual viewport.
    FloatPoint newLocation(location() + anchorDeltaUnusedByScroll);
    setScaleAndLocation(newPageScale, newLocation);
    return true;
}
// Modifies the top of the graphics layer tree to add layers needed to support
// the inner/outer viewport fixed-position model for pinch zoom. When finished,
// the tree will look like this (with * denoting added layers):
//
// *rootTransformLayer
//  +- *innerViewportContainerLayer (fixed pos container)
//  |   +- *overscrollElasticityLayer
//  |       +- *pageScaleLayer
//  |           +- *innerViewportScrollLayer
//  |               +-- overflowControlsHostLayer (root layer)
//  |                   +-- outerViewportContainerLayer (fixed pos container) [frame container layer in PaintLayerCompositor]
//  |                   |   +-- outerViewportScrollLayer [frame scroll layer in PaintLayerCompositor]
//  |                   |       +-- content layers ...
//  +- horizontalScrollbarLayer
//  +- verticalScrollbarLayer
//  +- scroll corner (non-overlay only)
//
void VisualViewport::attachToLayerTree(GraphicsLayer* currentLayerTreeRoot, GraphicsLayerFactory* graphicsLayerFactory)
{
    TRACE_EVENT1("blink", "VisualViewport::attachToLayerTree", "currentLayerTreeRoot", (bool)currentLayerTreeRoot);
    if (!currentLayerTreeRoot) {
        if (m_innerViewportScrollLayer)
            m_innerViewportScrollLayer->removeAllChildren();
        return;
    }

    if (currentLayerTreeRoot->parent() && currentLayerTreeRoot->parent() == m_innerViewportScrollLayer)
        return;

    if (!m_innerViewportScrollLayer) {
        ASSERT(!m_overlayScrollbarHorizontal
            && !m_overlayScrollbarVertical
            && !m_overscrollElasticityLayer
            && !m_pageScaleLayer
            && !m_innerViewportContainerLayer);

        // FIXME: The root transform layer should only be created on demand.
        m_rootTransformLayer = GraphicsLayer::create(graphicsLayerFactory, this);
        m_innerViewportContainerLayer = GraphicsLayer::create(graphicsLayerFactory, this);
        m_overscrollElasticityLayer = GraphicsLayer::create(graphicsLayerFactory, this);
        m_pageScaleLayer = GraphicsLayer::create(graphicsLayerFactory, this);
        m_innerViewportScrollLayer = GraphicsLayer::create(graphicsLayerFactory, this);
        m_overlayScrollbarHorizontal = GraphicsLayer::create(graphicsLayerFactory, this);
        m_overlayScrollbarVertical = GraphicsLayer::create(graphicsLayerFactory, this);

        ScrollingCoordinator* coordinator = frameHost().page().scrollingCoordinator();
        ASSERT(coordinator);
        coordinator->setLayerIsContainerForFixedPositionLayers(m_innerViewportScrollLayer.get(), true);

        // Set masks to bounds so the compositor doesn't clobber a manually
        // set inner viewport container layer size.
        m_innerViewportContainerLayer->setMasksToBounds(frameHost().settings().mainFrameClipsContent());
        m_innerViewportContainerLayer->setSize(m_size);

        m_innerViewportScrollLayer->platformLayer()->setScrollClipLayer(
            m_innerViewportContainerLayer->platformLayer());
        m_innerViewportScrollLayer->platformLayer()->setUserScrollable(true, true);

        m_rootTransformLayer->addChild(m_innerViewportContainerLayer.get());
        m_innerViewportContainerLayer->addChild(m_overscrollElasticityLayer.get());
        m_overscrollElasticityLayer->addChild(m_pageScaleLayer.get());
        m_pageScaleLayer->addChild(m_innerViewportScrollLayer.get());

        // Ensure this class is set as the scroll layer's ScrollableArea.
        coordinator->scrollableAreaScrollLayerDidChange(this);

        initializeScrollbars();
    }

    m_innerViewportScrollLayer->removeAllChildren();
    m_innerViewportScrollLayer->addChild(currentLayerTreeRoot);
}
예제 #3
0
bool VisualViewport::magnifyScaleAroundAnchor(float magnifyDelta,
                                              const FloatPoint& anchor) {
  const float oldPageScale = scale();
  const float newPageScale =
      frameHost().chromeClient().clampPageScaleFactorToLimits(magnifyDelta *
                                                              oldPageScale);
  if (newPageScale == oldPageScale)
    return false;
  if (!mainFrame() || !mainFrame()->view())
    return false;

  // Keep the center-of-pinch anchor in a stable position over the course
  // of the magnify.
  FloatPoint anchorAtOldScale = anchor.scaledBy(1.f / oldPageScale);
  FloatPoint anchorAtNewScale = anchor.scaledBy(1.f / newPageScale);
  FloatSize anchorDelta = anchorAtOldScale - anchorAtNewScale;

  // First try to use the anchor's delta to scroll the FrameView.
  FloatSize anchorDeltaUnusedByScroll = anchorDelta;

  // Manually bubble any remaining anchor delta up to the visual viewport.
  FloatPoint newLocation(FloatPoint(getScrollOffset()) +
                         anchorDeltaUnusedByScroll);
  setScaleAndLocation(newPageScale, newLocation);
  return true;
}
예제 #4
0
void Page::setPageScaleFactor(float scale, const IntPoint& origin)
{
    if (!mainFrame()->isLocalFrame())
        return;

    FrameView* view = deprecatedLocalMainFrame()->view();
    PinchViewport& viewport = frameHost().pinchViewport();

    if (scale != viewport.scale()) {
        viewport.setScale(scale);

        if (view && !settings().pinchVirtualViewportEnabled())
            view->setVisibleContentScaleFactor(scale);

        deprecatedLocalMainFrame()->deviceOrPageScaleFactorChanged();
        m_chrome->client().deviceOrPageScaleFactorChanged();

        // FIXME: In virtual-viewport pinch mode, scale doesn't change the fixed-pos viewport;
        // remove once it's the only pinch mode in town.
        if (view)
            view->viewportConstrainedVisibleContentSizeChanged(true, true);

        deprecatedLocalMainFrame()->loader().saveScrollState();
    }

    if (view && view->scrollPosition() != origin)
        view->notifyScrollPositionChanged(origin);
}
예제 #5
0
bool VisualViewport::didSetScaleOrLocation(float scale,
                                           const FloatPoint& location) {
  if (!mainFrame())
    return false;

  bool valuesChanged = false;

  if (scale != m_scale) {
    m_scale = scale;
    valuesChanged = true;
    frameHost().chromeClient().pageScaleFactorChanged();
    enqueueResizeEvent();
  }

  ScrollOffset clampedOffset = clampScrollOffset(toScrollOffset(location));

  if (clampedOffset != m_offset) {
    m_offset = clampedOffset;
    scrollAnimator().setCurrentOffset(m_offset);

    // SVG runs with accelerated compositing disabled so no
    // ScrollingCoordinator.
    if (ScrollingCoordinator* coordinator =
            frameHost().page().scrollingCoordinator())
      coordinator->scrollableAreaScrollLayerDidChange(this);

    if (!frameHost().settings().inertVisualViewport()) {
      if (Document* document = mainFrame()->document())
        document->enqueueScrollEventForNode(document);
    }

    enqueueScrollEvent();

    mainFrame()->view()->didChangeScrollOffset();
    valuesChanged = true;
  }

  if (!valuesChanged)
    return false;

  InspectorInstrumentation::didUpdateLayout(mainFrame());
  mainFrame()->loader().saveScrollState();

  clampToBoundaries();

  return true;
}
예제 #6
0
void VisualViewport::setupScrollbar(WebScrollbar::Orientation orientation) {
  bool isHorizontal = orientation == WebScrollbar::Horizontal;
  GraphicsLayer* scrollbarGraphicsLayer =
      isHorizontal ? m_overlayScrollbarHorizontal.get()
                   : m_overlayScrollbarVertical.get();
  std::unique_ptr<WebScrollbarLayer>& webScrollbarLayer =
      isHorizontal ? m_webOverlayScrollbarHorizontal
                   : m_webOverlayScrollbarVertical;

  ScrollbarThemeOverlay& theme = ScrollbarThemeOverlay::mobileTheme();
  int thumbThickness = theme.thumbThickness();
  int scrollbarThickness = theme.scrollbarThickness(RegularScrollbar);
  int scrollbarMargin = theme.scrollbarMargin();

  if (!webScrollbarLayer) {
    ScrollingCoordinator* coordinator =
        frameHost().page().scrollingCoordinator();
    ASSERT(coordinator);
    ScrollbarOrientation webcoreOrientation =
        isHorizontal ? HorizontalScrollbar : VerticalScrollbar;
    webScrollbarLayer = coordinator->createSolidColorScrollbarLayer(
        webcoreOrientation, thumbThickness, scrollbarMargin, false);

    // The compositor will control the scrollbar's visibility. Set to invisible
    // by default so scrollbars don't show up in layout tests.
    webScrollbarLayer->layer()->setOpacity(0);
    scrollbarGraphicsLayer->setContentsToPlatformLayer(
        webScrollbarLayer->layer());
    scrollbarGraphicsLayer->setDrawsContent(false);
  }

  int xPosition = isHorizontal ? 0
                               : m_innerViewportContainerLayer->size().width() -
                                     scrollbarThickness;
  int yPosition =
      isHorizontal
          ? m_innerViewportContainerLayer->size().height() - scrollbarThickness
          : 0;
  int width =
      isHorizontal
          ? m_innerViewportContainerLayer->size().width() - scrollbarThickness
          : scrollbarThickness;
  int height = isHorizontal ? scrollbarThickness
                            : m_innerViewportContainerLayer->size().height() -
                                  scrollbarThickness;

  // Use the GraphicsLayer to position the scrollbars.
  scrollbarGraphicsLayer->setPosition(IntPoint(xPosition, yPosition));
  scrollbarGraphicsLayer->setSize(FloatSize(width, height));
  scrollbarGraphicsLayer->setContentsRect(IntRect(0, 0, width, height));
}
void VisualViewport::registerLayersWithTreeView(WebLayerTreeView* layerTreeView) const
{
    TRACE_EVENT0("blink", "VisualViewport::registerLayersWithTreeView");
    ASSERT(layerTreeView);

    if (!mainFrame())
        return;

    ASSERT(frameHost().page().deprecatedLocalMainFrame()->contentLayoutObject());

    PaintLayerCompositor* compositor = frameHost().page().deprecatedLocalMainFrame()->contentLayoutObject()->compositor();
    // Get the outer viewport scroll layer.
    WebLayer* scrollLayer = compositor->scrollLayer() ? compositor->scrollLayer()->platformLayer() : 0;

    m_webOverlayScrollbarHorizontal->setScrollLayer(scrollLayer);
    m_webOverlayScrollbarVertical->setScrollLayer(scrollLayer);

    ASSERT(compositor);
    layerTreeView->registerViewportLayers(
        m_overscrollElasticityLayer->platformLayer(),
        m_pageScaleLayer->platformLayer(),
        m_innerViewportScrollLayer->platformLayer(),
        scrollLayer);
}
bool VisualViewport::shouldDisableDesktopWorkarounds() const
{
    if (!mainFrame() || !mainFrame()->view())
        return false;

    if (!mainFrame()->settings()->viewportEnabled())
        return false;

    // A document is considered adapted to small screen UAs if one of these holds:
    // 1. The author specified viewport has a constrained width that is equal to
    //    the initial viewport width.
    // 2. The author has disabled viewport zoom.
    const PageScaleConstraints& constraints = frameHost().pageScaleConstraintsSet().pageDefinedConstraints();

    return mainFrame()->view()->layoutSize().width() == m_size.width()
        || (constraints.minimumScale == constraints.maximumScale && constraints.minimumScale != -1);
}
예제 #9
0
void VisualViewport::initializeScrollbars() {
  // Do nothing if not attached to layer tree yet - will initialize upon attach.
  if (!m_innerViewportContainerLayer)
    return;

  if (visualViewportSuppliesScrollbars() &&
      !frameHost().settings().hideScrollbars()) {
    if (!m_overlayScrollbarHorizontal->parent())
      m_innerViewportContainerLayer->addChild(
          m_overlayScrollbarHorizontal.get());
    if (!m_overlayScrollbarVertical->parent())
      m_innerViewportContainerLayer->addChild(m_overlayScrollbarVertical.get());
  } else {
    m_overlayScrollbarHorizontal->removeFromParent();
    m_overlayScrollbarVertical->removeFromParent();
  }

  setupScrollbar(WebScrollbar::Horizontal);
  setupScrollbar(WebScrollbar::Vertical);
}
DoublePoint VisualViewport::maximumScrollPositionDouble() const
{
    if (!mainFrame())
        return IntPoint();

    // FIXME: We probably shouldn't be storing the bounds in a float. crbug.com/422331.
    FloatSize frameViewSize(contentsSize());

    if (m_topControlsAdjustment) {
        float minScale = frameHost().pageScaleConstraintsSet().finalConstraints().minimumScale;
        frameViewSize.expand(0, m_topControlsAdjustment / minScale);
    }

    frameViewSize.scale(m_scale);
    frameViewSize = flooredIntSize(frameViewSize);

    FloatSize viewportSize(m_size);
    viewportSize.expand(0, m_topControlsAdjustment);

    FloatSize maxPosition = frameViewSize - viewportSize;
    maxPosition.scale(1 / m_scale);
    return DoublePoint(maxPosition);
}
예제 #11
0
ScrollOffset VisualViewport::maximumScrollOffset() const {
  if (!mainFrame())
    return ScrollOffset();

  // TODO(bokan): We probably shouldn't be storing the bounds in a float.
  // crbug.com/470718.
  FloatSize frameViewSize(contentsSize());

  if (m_browserControlsAdjustment) {
    float minScale =
        frameHost().pageScaleConstraintsSet().finalConstraints().minimumScale;
    frameViewSize.expand(0, m_browserControlsAdjustment / minScale);
  }

  frameViewSize.scale(m_scale);
  frameViewSize = FloatSize(flooredIntSize(frameViewSize));

  FloatSize viewportSize(m_size);
  viewportSize.expand(0, ceilf(m_browserControlsAdjustment));

  FloatSize maxPosition = frameViewSize - viewportSize;
  maxPosition.scale(1 / m_scale);
  return ScrollOffset(maxPosition);
}
예제 #12
0
float Page::pageScaleFactor() const
{
    return frameHost().pinchViewport().scale();
}
LocalFrame* VisualViewport::mainFrame() const
{
    return frameHost().page().mainFrame() && frameHost().page().mainFrame()->isLocalFrame() ? frameHost().page().deprecatedLocalMainFrame() : 0;
}
HostWindow* VisualViewport::hostWindow() const
{
    return &frameHost().chromeClient();
}
bool VisualViewport::visualViewportSuppliesScrollbars() const
{
    return frameHost().settings().viewportMetaEnabled();
}
예제 #16
0
bool VisualViewport::scrollAnimatorEnabled() const {
  return frameHost().settings().scrollAnimatorEnabled();
}
예제 #17
0
CompositorAnimationTimeline* VisualViewport::compositorAnimationTimeline()
    const {
  ScrollingCoordinator* c = frameHost().page().scrollingCoordinator();
  return c ? c->compositorAnimationTimeline() : nullptr;
}