void QtViewportInteractionEngine::focusEditableArea(const QRectF& caretArea, const QRectF& targetArea)
{
    QRectF endArea = itemRectFromCSS(targetArea);

    qreal endItemScale = itemScaleFromCSS(innerBoundedCSSScale(2.0));
    const QRectF viewportRect = m_viewport->boundingRect();

    qreal x;
    const qreal borderOffset = 10;
    if ((endArea.width() + borderOffset) * endItemScale <= viewportRect.width()) {
        // Center the input field in the middle of the view, if it is smaller than
        // the view at the scale target.
        x = viewportRect.center().x() - endArea.width() * endItemScale / 2.0;
    } else {
        // Ensure that the caret always has borderOffset contents pixels to the right
        // of it, and secondarily (if possible), that the area has borderOffset
        // contents pixels to the left of it.
        qreal caretOffset = itemCoordFromCSS(caretArea.x()) - endArea.x();
        x = qMin(viewportRect.width() - (caretOffset + borderOffset) * endItemScale, borderOffset * endItemScale);
    }

    const QPointF hotspot = QPointF(endArea.x(), endArea.center().y());
    const QPointF viewportHotspot = QPointF(x, /* FIXME: visibleCenter */ viewportRect.center().y());

    QPointF endPosition = hotspot * endItemScale - viewportHotspot;
    QRectF endPosRange = computePosRangeForItemAtScale(endItemScale);

    endPosition = boundPosition(endPosRange.topLeft(), endPosition, endPosRange.bottomRight());

    QRectF endVisibleContentRect(endPosition / endItemScale, viewportRect.size() / endItemScale);

    animateItemRectVisible(endVisibleContentRect);
}
Example #2
0
void PageViewportControllerClientQt::focusEditableArea(const QRectF& caretArea, const QRectF& targetArea)
{
    // This can only happen as a result of a user interaction.
    ASSERT(m_controller->hadUserInteraction());

    const float editingFixedScale = 2;
    float targetScale = m_controller->innerBoundedViewportScale(editingFixedScale);
    const QRectF viewportRect = m_viewportItem->boundingRect();

    qreal x;
    const qreal borderOffset = 10;
    if ((targetArea.width() + borderOffset) * targetScale <= viewportRect.width()) {
        // Center the input field in the middle of the view, if it is smaller than
        // the view at the scale target.
        x = viewportRect.center().x() - targetArea.width() * targetScale / 2.0;
    } else {
        // Ensure that the caret always has borderOffset contents pixels to the right
        // of it, and secondarily (if possible), that the area has borderOffset
        // contents pixels to the left of it.
        qreal caretOffset = caretArea.x() - targetArea.x();
        x = qMin(viewportRect.width() - (caretOffset + borderOffset) * targetScale, borderOffset * targetScale);
    }

    const QPointF hotspot = QPointF(targetArea.x(), targetArea.center().y());
    const QPointF viewportHotspot = QPointF(x, /* FIXME: visibleCenter */ viewportRect.center().y());

    QPointF endPosition = hotspot - viewportHotspot / targetScale;
    endPosition = m_controller->boundContentsPositionAtScale(endPosition, targetScale);
    QRectF endVisibleContentRect(endPosition, viewportRect.size() / targetScale);

    animateContentRectVisible(endVisibleContentRect);
}
Example #3
0
bool QtViewportInteractionEngine::ensureContentWithinViewportBoundary(bool immediate)
{
    ASSERT(m_suspendCount);

    if (scrollAnimationActive() || scaleAnimationActive())
        return false;

    qreal endItemScale = itemScaleFromCSS(innerBoundedCSSScale(currentCSSScale()));

    const QRectF viewportRect = m_viewport->boundingRect();
    QPointF viewportHotspot = viewportRect.center();

    QPointF endPosition = m_viewport->mapToWebContent(viewportHotspot) * endItemScale - viewportHotspot;

    QRectF endPosRange = computePosRangeForItemAtScale(endItemScale);
    endPosition = boundPosition(endPosRange.topLeft(), endPosition, endPosRange.bottomRight());

    QRectF endVisibleContentRect(endPosition / endItemScale, viewportRect.size() / endItemScale);

    if (immediate) {
        setItemRectVisible(endVisibleContentRect);
        return true;
    }
    return !animateItemRectVisible(endVisibleContentRect);
}
Example #4
0
void QtViewportInteractionEngine::zoomToAreaGestureEnded(const QPointF& touchPoint, const QRectF& targetArea)
{
    if (!targetArea.isValid())
        return;

    if (scrollAnimationActive() || scaleAnimationActive())
        return;

    const int margin = 10; // We want at least a little bit or margin.
    QRectF endArea = itemRectFromCSS(targetArea.adjusted(-margin, -margin, margin, margin));

    const QRectF viewportRect = m_viewport->boundingRect();

    qreal targetCSSScale = cssScaleFromItem(viewportRect.size().width() / endArea.size().width());
    qreal endItemScale = itemScaleFromCSS(innerBoundedCSSScale(qMin(targetCSSScale, qreal(2.5))));

    // We want to end up with the target area filling the whole width of the viewport (if possible),
    // and centralized vertically where the user requested zoom. Thus our hotspot is the center of
    // the targetArea x-wise and the requested zoom position, y-wise.
    const QPointF hotspot = QPointF(endArea.center().x(), touchPoint.y() * m_constraints.devicePixelRatio);
    const QPointF viewportHotspot = viewportRect.center();

    QPointF endPosition = hotspot * endItemScale - viewportHotspot;

    QRectF endPosRange = computePosRangeForItemAtScale(endItemScale);
    endPosition = boundPosition(endPosRange.topLeft(), endPosition, endPosRange.bottomRight());

    QRectF endVisibleContentRect(endPosition / endItemScale, viewportRect.size() / endItemScale);

    animateItemRectVisible(endVisibleContentRect);
}
Example #5
0
QRectF QtViewportHandler::initialRect() const
{
    ASSERT(m_rawAttributes.initialScale > 0);

    qreal endItemScale = itemScaleFromCSS(innerBoundedCSSScale(m_rawAttributes.initialScale));
    const QRectF viewportRect = m_viewportItem->boundingRect();
    QRectF endVisibleContentRect(QPointF(0, 0), viewportRect.size() / endItemScale);

    return endVisibleContentRect;
}
Example #6
0
void PageViewportController::pageDidRequestScroll(const IntPoint& cssPosition)
{
    // Ignore the request if suspended. Can only happen due to delay in event delivery.
    if (m_hasSuspendedContent)
        return;

    FloatRect endVisibleContentRect(clampViewportToContents(cssPosition, m_effectiveScale), viewportSizeInContentsCoordinates());
    if (m_lastFrameCoveredRect.intersects(endVisibleContentRect))
        m_client->setViewportPosition(endVisibleContentRect.location());
    else
        // Keep the unclamped position in case the contents size is changed later on.
        applyPositionAfterRenderingContents(cssPosition);
}
void QtViewportInteractionEngine::pagePositionRequest(const QPoint& pagePosition)
{
    // Ignore the request if suspended. Can only happen due to delay in event delivery.
    if (m_suspendCount)
        return;

    qreal endItemScale = m_content->contentsScale(); // Stay at same scale.

    QRectF endPosRange = computePosRangeForItemAtScale(endItemScale);
    QPointF endPosition = boundPosition(endPosRange.topLeft(), pagePosition * endItemScale, endPosRange.bottomRight());

    QRectF endVisibleContentRect(endPosition / endItemScale, m_viewport->boundingRect().size() / endItemScale);

    setItemRectVisible(endVisibleContentRect);
}
Example #8
0
QRectF QtViewportHandler::nearestValidBounds() const
{
    qreal endItemScale = itemScaleFromCSS(innerBoundedCSSScale(currentCSSScale()));

    const QRectF viewportRect = m_viewportItem->boundingRect();
    QPointF viewportHotspot = viewportRect.center();

    QPointF endPosition = m_viewportItem->mapToWebContent(viewportHotspot) * endItemScale - viewportHotspot;

    QRectF endPosRange = computePosRangeForPageItemAtScale(endItemScale);
    endPosition = boundPosition(endPosRange.topLeft(), endPosition, endPosRange.bottomRight());

    QRectF endVisibleContentRect(endPosition / endItemScale, viewportRect.size() / endItemScale);

    return endVisibleContentRect;
}
Example #9
0
void QtViewportHandler::pageContentPositionRequested(const QPoint& cssPosition)
{
    // Ignore the request if suspended. Can only happen due to delay in event delivery.
    if (m_suspendCount)
        return;

    qreal endItemScale = m_pageItem->contentsScale(); // Stay at same scale.

    QRectF endPosRange = computePosRangeForPageItemAtScale(endItemScale);
    QPointF endPosition = boundPosition(endPosRange.topLeft(), cssPosition * endItemScale, endPosRange.bottomRight());

    QRectF endVisibleContentRect(endPosition / endItemScale, m_viewportItem->boundingRect().size() / endItemScale);

    ViewportUpdateDeferrer guard(this);
    setPageItemRectVisible(endVisibleContentRect);
}
Example #10
0
void QtViewportHandler::zoomToAreaGestureEnded(const QPointF& touchPoint, const QRectF& targetArea)
{
    // This can only happen as a result of a user interaction.
    ASSERT(m_hadUserInteraction);

    if (!targetArea.isValid())
        return;

    if (m_suspendCount)
        return;

    const int margin = 10; // We want at least a little bit of margin.
    QRectF endArea = itemRectFromCSS(targetArea.adjusted(-margin, -margin, margin, margin));

    const QRectF viewportRect = m_viewportItem->boundingRect();

    qreal targetCSSScale = viewportRect.size().width() / endArea.size().width();
    qreal endCSSScale = innerBoundedCSSScale(qMin(targetCSSScale, qreal(2.5)));
    qreal endItemScale = itemScaleFromCSS(endCSSScale);
    qreal currentScale = m_pageItem->contentsScale();

    // We want to end up with the target area filling the whole width of the viewport (if possible),
    // and centralized vertically where the user requested zoom. Thus our hotspot is the center of
    // the targetArea x-wise and the requested zoom position, y-wise.
    const QPointF hotspot = QPointF(endArea.center().x(), itemCoordFromCSS(touchPoint.y()));
    const QPointF viewportHotspot = viewportRect.center();

    QPointF endPosition = hotspot * endCSSScale - viewportHotspot;

    QRectF endPosRange = computePosRangeForPageItemAtScale(endItemScale);
    endPosition = boundPosition(endPosRange.topLeft(), endPosition, endPosRange.bottomRight());

    QRectF endVisibleContentRect(endPosition / endItemScale, viewportRect.size() / endItemScale);

    enum { ZoomIn, ZoomBack, ZoomOut, NoZoom } zoomAction = ZoomIn;

    if (!m_scaleStack.isEmpty()) {
        // Zoom back out if attempting to scale to the same current scale, or
        // attempting to continue scaling out from the inner most level.
        // Use fuzzy compare with a fixed error to be able to deal with largish differences due to pixel rounding.
        if (fuzzyCompare(endItemScale, currentScale, 0.01)) {
            // If moving the viewport would expose more of the targetRect and move at least 40 pixels, update position but do not scale out.
            QRectF currentContentRect(m_viewportItem->contentPos() / currentScale, viewportRect.size() / currentScale);
            QRectF targetIntersection = endVisibleContentRect.intersected(targetArea);
            if (!currentContentRect.contains(targetIntersection) && (qAbs(endVisibleContentRect.top() - currentContentRect.top()) >= 40 || qAbs(endVisibleContentRect.left() - currentContentRect.left()) >= 40))
                zoomAction = NoZoom;
            else
                zoomAction = ZoomBack;
        } else if (fuzzyCompare(endItemScale, m_zoomOutScale, 0.01))
            zoomAction = ZoomBack;
        else if (endItemScale < currentScale)
            zoomAction = ZoomOut;
    }

    switch (zoomAction) {
    case ZoomIn:
        m_scaleStack.append(ScaleStackItem(currentScale, m_viewportItem->contentPos().x()));
        m_zoomOutScale = endItemScale;
        break;
    case ZoomBack: {
        ScaleStackItem lastScale = m_scaleStack.takeLast();
        endItemScale = lastScale.scale;
        endCSSScale = cssScaleFromItem(lastScale.scale);
        // Recalculate endPosition and bound it according to new scale.
        endPosition.setY(hotspot.y() * endCSSScale - viewportHotspot.y());
        endPosition.setX(lastScale.xPosition);
        endPosRange = computePosRangeForPageItemAtScale(endItemScale);
        endPosition = boundPosition(endPosRange.topLeft(), endPosition, endPosRange.bottomRight());
        endVisibleContentRect = QRectF(endPosition / endItemScale, viewportRect.size() / endItemScale);
        break;
    }
    case ZoomOut:
        // Unstack all scale-levels deeper than the new level, so a zoom-back won't end up zooming in.
        while (!m_scaleStack.isEmpty() && m_scaleStack.last().scale >= endItemScale)
            m_scaleStack.removeLast();
        m_zoomOutScale = endItemScale;
        break;
    case NoZoom:
        break;
    }

    animatePageItemRectVisible(endVisibleContentRect);
}
Example #11
0
void PageViewportControllerClientQt::zoomToAreaGestureEnded(const QPointF& touchPoint, const QRectF& targetArea)
{
    // This can only happen as a result of a user interaction.
    ASSERT(m_controller->hadUserInteraction());

    if (!targetArea.isValid())
        return;

    if (m_scrollChange.inProgress() || m_scaleChange.inProgress())
        return;

    const float margin = 10; // We want at least a little bit of margin.
    QRectF endArea = targetArea.adjusted(-margin, -margin, margin, margin);

    const QRectF viewportRect = m_viewportItem->boundingRect();

    qreal minViewportScale = qreal(2.5);
    qreal targetScale = viewportRect.size().width() / endArea.size().width();
    targetScale = m_controller->innerBoundedViewportScale(qMin(minViewportScale, targetScale));
    qreal currentScale = m_pageItem->contentsScale();

    // We want to end up with the target area filling the whole width of the viewport (if possible),
    // and centralized vertically where the user requested zoom. Thus our hotspot is the center of
    // the targetArea x-wise and the requested zoom position, y-wise.
    const QPointF hotspot = QPointF(endArea.center().x(), touchPoint.y());
    const QPointF viewportHotspot = viewportRect.center();

    QPointF endPosition = hotspot - viewportHotspot / targetScale;
    endPosition = m_controller->clampViewportToContents(endPosition, targetScale);
    QRectF endVisibleContentRect(endPosition, viewportRect.size() / targetScale);

    enum { ZoomIn, ZoomBack, ZoomOut, NoZoom } zoomAction = ZoomIn;

    // Zoom back out if attempting to scale to the same current scale, or
    // attempting to continue scaling out from the inner most level.
    // Use fuzzy compare with a fixed error to be able to deal with largish differences due to pixel rounding.
    if (!m_scaleStack.isEmpty() && fuzzyCompare(targetScale, currentScale, 0.01)) {
        // If moving the viewport would expose more of the targetRect and move at least 40 pixels, update position but do not scale out.
        QRectF currentContentRect(m_viewportItem->mapRectToWebContent(viewportRect));
        QRectF targetIntersection = endVisibleContentRect.intersected(targetArea);
        if (!currentContentRect.contains(targetIntersection)
            && (qAbs(endVisibleContentRect.top() - currentContentRect.top()) >= 40
            || qAbs(endVisibleContentRect.left() - currentContentRect.left()) >= 40))
            zoomAction = NoZoom;
        else
            zoomAction = ZoomBack;
    } else if (fuzzyCompare(targetScale, m_zoomOutScale, 0.01))
        zoomAction = ZoomBack;
    else if (targetScale < currentScale)
        zoomAction = ZoomOut;

    switch (zoomAction) {
    case ZoomIn:
        m_scaleStack.append(ScaleStackItem(currentScale, m_viewportItem->contentPos().x() / currentScale));
        m_zoomOutScale = targetScale;
        break;
    case ZoomBack: {
        if (m_scaleStack.isEmpty()) {
            targetScale = m_controller->minimumContentsScale();
            endPosition.setY(hotspot.y() - viewportHotspot.y() / targetScale);
            endPosition.setX(0);
            m_zoomOutScale = 0;
        } else {
            ScaleStackItem lastScale = m_scaleStack.takeLast();
            targetScale = lastScale.scale;
            // Recalculate endPosition and clamp it according to the new scale.
            endPosition.setY(hotspot.y() - viewportHotspot.y() / targetScale);
            endPosition.setX(lastScale.xPosition);
        }
        endPosition = m_controller->clampViewportToContents(endPosition, targetScale);
        endVisibleContentRect = QRectF(endPosition, viewportRect.size() / targetScale);
        break;
    }
    case ZoomOut:
        // Unstack all scale-levels deeper than the new level, so a zoom-back won't end up zooming in.
        while (!m_scaleStack.isEmpty() && m_scaleStack.last().scale >= targetScale)
            m_scaleStack.removeLast();
        m_zoomOutScale = targetScale;
        break;
    case NoZoom:
        break;
    }

    animateContentRectVisible(endVisibleContentRect);
}