From 27441054197d0ecff6b83e7e6511e0d6955f4593 Mon Sep 17 00:00:00 2001 From: Pekka Vuorela Date: Thu, 8 Dec 2011 14:52:19 +0200 Subject: [PATCH] Protect QAbstractTextDocumentLayout::anchorAt() from preedit Previously the method didn't take into account that hitTest() returns visual index, i.e. containing the preedit, and thus was easily hitting assertion. Need to compensate for that before checking for actual link. Change-Id: I119e7f91088b4db9d347a3da338f6df915ce9719 Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/gui/text/qabstracttextdocumentlayout.cpp | 15 +++++++++ .../tst_qabstracttextdocumentlayout.cpp | 32 +++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/src/gui/text/qabstracttextdocumentlayout.cpp b/src/gui/text/qabstracttextdocumentlayout.cpp index 589c0f701f..e14cfe0f82 100644 --- a/src/gui/text/qabstracttextdocumentlayout.cpp +++ b/src/gui/text/qabstracttextdocumentlayout.cpp @@ -577,6 +577,21 @@ QString QAbstractTextDocumentLayout::anchorAt(const QPointF& pos) const if (cursorPos == -1) return QString(); + // compensate for preedit in the hit text block + QTextBlock block = document()->firstBlock(); + while (block.isValid()) { + QRectF blockBr = blockBoundingRect(block); + if (blockBr.contains(pos)) { + QTextLayout *layout = block.layout(); + int relativeCursorPos = cursorPos - block.position(); + const int preeditLength = layout ? layout->preeditAreaText().length() : 0; + if (preeditLength > 0 && relativeCursorPos > layout->preeditAreaPosition()) + cursorPos -= qMin(cursorPos - layout->preeditAreaPosition(), preeditLength); + break; + } + block = block.next(); + } + QTextDocumentPrivate *pieceTable = qobject_cast(parent())->docHandle(); QTextDocumentPrivate::FragmentIterator it = pieceTable->find(cursorPos); QTextCharFormat fmt = pieceTable->formatCollection()->charFormat(it->format); diff --git a/tests/auto/gui/text/qabstracttextdocumentlayout/tst_qabstracttextdocumentlayout.cpp b/tests/auto/gui/text/qabstracttextdocumentlayout/tst_qabstracttextdocumentlayout.cpp index c609b4a1ed..a33e3cd13b 100644 --- a/tests/auto/gui/text/qabstracttextdocumentlayout/tst_qabstracttextdocumentlayout.cpp +++ b/tests/auto/gui/text/qabstracttextdocumentlayout/tst_qabstracttextdocumentlayout.cpp @@ -47,6 +47,7 @@ #include #include #include +#include class tst_QAbstractTextDocumentLayout : public QObject { @@ -59,6 +60,7 @@ public: private slots: void getSetCheck(); void maximumBlockCount(); + void anchorAt(); }; tst_QAbstractTextDocumentLayout::tst_QAbstractTextDocumentLayout() @@ -152,5 +154,35 @@ void tst_QAbstractTextDocumentLayout::maximumBlockCount() QCOMPARE(layout.blockCount, 10); } +void tst_QAbstractTextDocumentLayout::anchorAt() +{ + QTextDocument doc; + doc.setHtml("foo"); + QAbstractTextDocumentLayout *documentLayout = doc.documentLayout(); + QTextBlock firstBlock = doc.begin(); + QTextLayout *layout = firstBlock.layout(); + layout->setPreeditArea(doc.toPlainText().length(), "xxx"); + + doc.setPageSize(QSizeF(1000, 1000)); + QFontMetrics metrics(layout->font()); + QPointF blockStart = documentLayout->blockBoundingRect(firstBlock).topLeft(); + + // anchorAt on start returns link + QRect linkBr = metrics.boundingRect("foo"); + QPointF linkPoint(linkBr.width() + blockStart.x(), (linkBr.height() / 2) + blockStart.y()); + QCOMPARE(documentLayout->anchorAt(linkPoint), QString("link")); + + // anchorAt() on top of preedit at end should not assert + QRect preeditBr = metrics.boundingRect(doc.toPlainText() + "xx"); + QPointF preeditPoint(preeditBr.width() + blockStart.x(), (preeditBr.height() / 2) + blockStart.y()); + QCOMPARE(documentLayout->anchorAt(preeditPoint), QString()); + + // preedit at start should not return link + layout->setPreeditArea(0, "xxx"); + preeditBr = metrics.boundingRect("xx"); + preeditPoint = QPointF(preeditBr.width() + blockStart.x(), (preeditBr.height() / 2) + blockStart.y()); + QCOMPARE(documentLayout->anchorAt(preeditPoint), QString()); +} + QTEST_MAIN(tst_QAbstractTextDocumentLayout) #include "tst_qabstracttextdocumentlayout.moc"