Skip to content

Commit

Permalink
Fix rounding issue when using expensive scaling
Browse files Browse the repository at this point in the history
  • Loading branch information
jdpurcell committed Dec 23, 2024
1 parent e0239b8 commit 5716a52
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 16 deletions.
31 changes: 18 additions & 13 deletions src/qvgraphicsview.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,10 @@ void QVGraphicsView::zoomAbsolute(const qreal absoluteLevel, const QPoint &pos)
zoomLevel = absoluteLevel;

// If we are zooming in, we have a point to zoom towards, the mouse is on top of the viewport, and cursor zooming is enabled
if (getContentToViewportRatio() >= 1.0 && pos != QPoint(-1, -1) && underMouse() && isCursorZoomEnabled)
const QSize contentSize = getContentRect().size();
const QSize viewportSize = getUsableViewportRect(true).size();
const bool reachedViewportSize = contentSize.width() >= viewportSize.width() || contentSize.height() >= viewportSize.height();
if (reachedViewportSize && pos != QPoint(-1, -1) && underMouse() && isCursorZoomEnabled)
{
const QPointF p1mouse = mapFromScene(scenePos);
const QPointF move = p1mouse - pos;
Expand All @@ -335,8 +338,10 @@ void QVGraphicsView::applyExpensiveScaling()
if (!isScalingEnabled || !getCurrentFileDetails().isPixmapLoaded)
return;

// If we are above maximum scaling size
if (getContentToViewportRatio() > (isScalingTwoEnabled ? 3.0 : 1.00001))
// Don't go over the maximum scaling size - small tolerance added to cover rounding errors
const QSize contentSize = getContentRect().size();
const QSize maxSize = getUsableViewportRect(true).size() * (isScalingTwoEnabled ? 3 : 1) + QSize(2, 2);
if (contentSize.width() > maxSize.width() || contentSize.height() > maxSize.height())
{
// Return to original size
removeExpensiveScaling();
Expand Down Expand Up @@ -459,7 +464,7 @@ void QVGraphicsView::originalSize()
void QVGraphicsView::centerImage()
{
const QRect viewRect = getUsableViewportRect();
const QRect contentRect = getContentRect().toRect();
const QRect contentRect = getContentRect();
const int hOffset = isRightToLeft() ?
horizontalScrollBar()->minimum() + horizontalScrollBar()->maximum() - contentRect.left() :
contentRect.left();
Expand Down Expand Up @@ -572,9 +577,16 @@ QSizeF QVGraphicsView::getEffectiveOriginalSize() const
return getTransformWithNoScaling().mapRect(QRectF(QPoint(), getCurrentFileDetails().loadedPixmapSize)).size() * getDpiAdjustment();
}

QRectF QVGraphicsView::getContentRect() const
QRect QVGraphicsView::getContentRect() const
{
return transform().mapRect(loadedPixmapItem->boundingRect());
// Avoid using loadedPixmapItem and the active transform because the pixmap may have expensive scaling applied
// which introduces a rounding error to begin with, and even worse, the error will be magnified if we're in the
// the process of zooming in and haven't re-applied the expensive scaling yet. If that's the case, callers need
// to know what the content rect will be once the dust settles rather than what's being temporarily displayed.
const QRectF loadedPixmapBoundingRect = QRectF(QPoint(), getCurrentFileDetails().loadedPixmapSize);
const qreal effectiveTransformScale = zoomLevel * appliedDpiAdjustment;
const QTransform effectiveTransform = getTransformWithNoScaling().scale(effectiveTransformScale, effectiveTransformScale);
return effectiveTransform.mapRect(loadedPixmapBoundingRect).toRect();
}

QRect QVGraphicsView::getUsableViewportRect(const bool addOverscan) const
Expand All @@ -591,13 +603,6 @@ QRect QVGraphicsView::getUsableViewportRect(const bool addOverscan) const
return rect;
}

qreal QVGraphicsView::getContentToViewportRatio() const
{
const QSizeF contentSize = getContentRect().size();
const QSizeF viewportSize = getUsableViewportRect(true).size();
return qMax(contentSize.width() / viewportSize.width(), contentSize.height() / viewportSize.height());
}

void QVGraphicsView::setTransformScale(qreal value)
{
#ifdef Q_OS_WIN
Expand Down
4 changes: 1 addition & 3 deletions src/qvgraphicsview.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,12 +102,10 @@ class QVGraphicsView : public QGraphicsView

bool event(QEvent *event) override;

QRectF getContentRect() const;
QRect getContentRect() const;

QRect getUsableViewportRect(const bool addOverscan = false) const;

qreal getContentToViewportRatio() const;

void setTransformScale(qreal absoluteScale);

QTransform getTransformWithNoScaling() const;
Expand Down

0 comments on commit 5716a52

Please sign in to comment.