From b3bb20b8bca2ff3ed23c97086132439c66e523dc Mon Sep 17 00:00:00 2001 From: Tang Haixiang Date: Wed, 27 Oct 2021 18:59:33 +0800 Subject: [PATCH] QTextDocumentLayout: Account for topMargin when hit-testing When TopMargin is set in TextBlock and the mouse click position is between Margin (the mouse is not on the textrect), the cursor will usually jump to the end. So topMargin should be considered when hitTest() calculates coordinates. Fixes: QTBUG-91774 Change-Id: I231377263855b9cd7152684203fc4ed2e9299bb9 Reviewed-by: Volker Hilsheimer Reviewed-by: Tang Haixiang Reviewed-by: Eskil Abrahamsen Blomfeldt (cherry picked from commit 8aae49019d7386c1abd6cd32f7ccb68c264c0288) --- src/gui/text/qtextdocumentlayout.cpp | 2 +- .../tst_qtextdocumentlayout.cpp | 37 +++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/gui/text/qtextdocumentlayout.cpp b/src/gui/text/qtextdocumentlayout.cpp index db3738ba97a..714632ba587 100644 --- a/src/gui/text/qtextdocumentlayout.cpp +++ b/src/gui/text/qtextdocumentlayout.cpp @@ -794,7 +794,7 @@ QTextDocumentLayoutPrivate::hitTest(const QTextBlock &bl, const QFixedPoint &poi textrect.translate(tl->position()); qCDebug(lcHit) << " checking block" << bl.position() << "point=" << point.toPointF() << " tlrect" << textrect; *position = bl.position(); - if (point.y.toReal() < textrect.top()) { + if (point.y.toReal() < textrect.top() - bl.blockFormat().topMargin()) { qCDebug(lcHit) << " before pos=" << *position; return PointBefore; } else if (point.y.toReal() > textrect.bottom()) { diff --git a/tests/auto/gui/text/qtextdocumentlayout/tst_qtextdocumentlayout.cpp b/tests/auto/gui/text/qtextdocumentlayout/tst_qtextdocumentlayout.cpp index 01c4005bfe9..010fe002d49 100644 --- a/tests/auto/gui/text/qtextdocumentlayout/tst_qtextdocumentlayout.cpp +++ b/tests/auto/gui/text/qtextdocumentlayout/tst_qtextdocumentlayout.cpp @@ -33,6 +33,7 @@ private slots: void floatingTablePageBreak(); void imageAtRightAlignedTab(); void blockVisibility(); + void testHitTest(); void largeImage(); @@ -380,5 +381,41 @@ void tst_QTextDocumentLayout::largeImage() } } +void tst_QTextDocumentLayout::testHitTest() +{ + QTextDocument document; + QTextCursor cur(&document); + int topMargin = 20; + + //insert 500 blocks into textedit + for (int i = 0; i < 500; i++) { + cur.insertBlock(); + cur.insertHtml(QString("block %1").arg(i)); + } + + //randomly set half the blocks invisible + QTextBlock blk=document.begin(); + for (int i = 0; i < 500; i++) { + if (i % 7) + blk.setVisible(0); + blk = blk.next(); + } + + //set margin for all blocks (not strictly necessary, but makes easier to click in between blocks) + QTextBlockFormat blkfmt; + blkfmt.setTopMargin(topMargin); + cur.movePosition(QTextCursor::Start); + cur.movePosition(QTextCursor::End, QTextCursor::KeepAnchor); + cur.mergeBlockFormat(blkfmt); + + for (int y = cur.selectionStart(); y < cur.selectionEnd(); y += 10) { + QPoint mousePoint(1, y); + int cursorPos = document.documentLayout()->hitTest(mousePoint, Qt::FuzzyHit); + int positionY = document.findBlock(cursorPos).layout()->position().toPoint().y(); + //mousePoint is in the rect of the current Block + QVERIFY(positionY - topMargin <= y); + } +} + QTEST_MAIN(tst_QTextDocumentLayout) #include "tst_qtextdocumentlayout.moc"