aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/quick/items/qquicktextedit.cpp23
-rw-r--r--src/quick/items/qquicktextedit_p_p.h4
-rw-r--r--tests/auto/quick/qquicktextedit/data/viewport.qml2
-rw-r--r--tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp38
4 files changed, 52 insertions, 15 deletions
diff --git a/src/quick/items/qquicktextedit.cpp b/src/quick/items/qquicktextedit.cpp
index 9ef041bbb1..d0614bbeff 100644
--- a/src/quick/items/qquicktextedit.cpp
+++ b/src/quick/items/qquicktextedit.cpp
@@ -2087,7 +2087,7 @@ QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *
QQuickTextNodeEngine engine;
QQuickTextNodeEngine frameDecorationsEngine;
- if (!oldNode || nodeIterator < d->textNodeMap.end()) {
+ if (!oldNode || nodeIterator < d->textNodeMap.end() || d->textNodeMap.isEmpty()) {
if (!oldNode)
rootNode = new RootNode;
@@ -2184,9 +2184,10 @@ QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *
QTextFrame::iterator it = textFrame->begin();
while (!it.atEnd()) {
QTextBlock block = it.currentBlock();
- ++it;
- if (block.position() < firstDirtyPos)
+ if (block.position() < firstDirtyPos) {
+ ++it;
continue;
+ }
if (!engine.hasContents())
nodeOffset = d->document->documentLayout()->blockBoundingRect(block).topLeft();
@@ -2199,6 +2200,21 @@ QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *
inView = coveredRegion.bottom() > viewport.top();
}
if (d->firstBlockInViewport < 0 && inView) {
+ // During backward scrolling, we need to iterate backwards from textNodeMap.begin() to fill the top of the viewport.
+ if (coveredRegion.top() > viewport.top() + 1) {
+ qCDebug(lcVP) << "checking backwards from block" << block.blockNumber() << "@" << nodeOffset.y() << coveredRegion;
+ while (it != textFrame->begin() && it.currentBlock().layout() &&
+ it.currentBlock().layout()->boundingRect().top() + nodeOffset.y() > viewport.top())
+ --it;
+ if (!it.currentBlock().layout())
+ ++it;
+ if (Q_LIKELY(it.currentBlock().layout())) {
+ block = it.currentBlock();
+ coveredRegion = block.layout()->boundingRect().adjusted(nodeOffset.x(), nodeOffset.y(), nodeOffset.x(), nodeOffset.y());
+ } else {
+ qCWarning(lcVP) << "failed to find a text block with layout during back-scrolling";
+ }
+ }
qCDebug(lcVP) << "first block in viewport" << block.blockNumber() << "@" << nodeOffset.y() << coveredRegion;
d->firstBlockInViewport = block.blockNumber();
if (block.layout())
@@ -2240,6 +2256,7 @@ QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *
resetEngine(&engine, d->color, d->selectedTextColor, d->selectionColor);
nodeStart = block.next().position();
}
+ ++it;
}
}
if (Q_LIKELY(node && !node->parent()))
diff --git a/src/quick/items/qquicktextedit_p_p.h b/src/quick/items/qquicktextedit_p_p.h
index b1937dab9e..2381b46a05 100644
--- a/src/quick/items/qquicktextedit_p_p.h
+++ b/src/quick/items/qquicktextedit_p_p.h
@@ -190,8 +190,8 @@ public:
int lastSelectionStart;
int lastSelectionEnd;
int lineCount;
- int firstBlockInViewport = -1;
- int firstBlockPastViewport = -1;
+ int firstBlockInViewport = -1; // only for the autotest; can be wrong after scrolling sometimes
+ int firstBlockPastViewport = -1; // only for the autotest
QRectF renderedRegion;
enum UpdateType {
diff --git a/tests/auto/quick/qquicktextedit/data/viewport.qml b/tests/auto/quick/qquicktextedit/data/viewport.qml
index c7c1dea526..4c7ffb88c0 100644
--- a/tests/auto/quick/qquicktextedit/data/viewport.qml
+++ b/tests/auto/quick/qquicktextedit/data/viewport.qml
@@ -10,7 +10,7 @@ Item {
border.color: "red"
TextEdit {
- font.pointSize: 10
+ font.pixelSize: 10
cursorDelegate: Rectangle {
border.color: "green"
border.width: 2
diff --git a/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp b/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp
index 812b541cb0..ccdf3e6b92 100644
--- a/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp
+++ b/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp
@@ -3693,6 +3693,8 @@ void tst_qquicktextedit::largeTextObservesViewport_data()
QTest::addColumn<QQuickTextEdit::TextFormat>("textFormat");
QTest::addColumn<bool>("parentIsViewport");
QTest::addColumn<int>("cursorPos");
+ QTest::addColumn<int>("scrollDelta"); // non-zero to move TextEdit in viewport
+
QTest::addColumn<int>("expectedBlockTolerance");
QTest::addColumn<int>("expectedBlocksAboveViewport");
QTest::addColumn<int>("expectedBlocksPastViewport");
@@ -3715,10 +3717,12 @@ void tst_qquicktextedit::largeTextObservesViewport_data()
// by default, the root item acts as the viewport:
// QQuickTextEdit doesn't populate lines of text beyond the bottom of the window
// cursor position 1000 is on line 121
- QTest::newRow("default plain text") << text << QQuickTextEdit::PlainText << false << 1000 << 4 << 115 << 147 << 1700 << 2700;
+ QTest::newRow("default plain text") << text << QQuickTextEdit::PlainText << false << 1000 << 0
+ << 5 << 114 << 155 << 1200 << 2200;
// make the rectangle into a viewport item, and move the text upwards:
// QQuickTextEdit doesn't populate lines of text beyond the bottom of the viewport rectangle
- QTest::newRow("clipped plain text") << text << QQuickTextEdit::PlainText << true << 1000 << 4 << 123 << 141 << 1800 << 2600;
+ QTest::newRow("clipped plain text") << text << QQuickTextEdit::PlainText << true << 1000 << 0
+ << 5 << 123 << 147 << 1200 << 2100;
{
QStringList lines;
@@ -3741,12 +3745,21 @@ void tst_qquicktextedit::largeTextObservesViewport_data()
// by default, the root item acts as the viewport:
// QQuickTextEdit doesn't populate blocks beyond the bottom of the window
- QTest::newRow("default styled text") << text << QQuickTextEdit::RichText << false << 1000 << 4 << 123 << 141 << 3200 << 4100;
+ QTest::newRow("default styled text") << text << QQuickTextEdit::RichText << false << 1000 << 0
+ << 120 << 7 << 143 << 2700 << 3700;
// make the rectangle into a viewport item, and move the text upwards:
// QQuickTextEdit doesn't populate blocks that don't intersect the viewport rectangle
- QTest::newRow("clipped styled text") << text << QQuickTextEdit::RichText << true << 1000 << 4 << 127 << 138 << 3300 << 4100;
+ QTest::newRow("clipped styled text") << text << QQuickTextEdit::RichText << true << 1000 << 0
+ << 3 << 127 << 139 << 2800 << 3600;
// get the "chapter 2" heading into the viewport
- QTest::newRow("heading visible") << text << QQuickTextEdit::RichText << true << 780 << 4 << 102 << 112 << 2600 << 3300;
+ QTest::newRow("heading visible") << text << QQuickTextEdit::RichText << true << 800 << 0
+ << 3 << 105 << 116 << 2300 << 3000;
+ // get the "chapter 2" heading into the viewport, and then scroll backwards
+ QTest::newRow("scroll backwards") << text << QQuickTextEdit::RichText << true << 800 << 20
+ << 3 << 104 << 116 << 2200 << 3000;
+ // get the "chapter 2" heading into the viewport, and then scroll forwards
+ QTest::newRow("scroll forwards") << text << QQuickTextEdit::RichText << true << 800 << -50
+ << 3 << 107 << 119 << 2300 << 3100;
}
void tst_qquicktextedit::largeTextObservesViewport()
@@ -3759,6 +3772,7 @@ void tst_qquicktextedit::largeTextObservesViewport()
QFETCH(QQuickTextEdit::TextFormat, textFormat);
QFETCH(bool, parentIsViewport);
QFETCH(int, cursorPos);
+ QFETCH(int, scrollDelta);
QFETCH(int, expectedBlockTolerance);
QFETCH(int, expectedBlocksAboveViewport);
QFETCH(int, expectedBlocksPastViewport);
@@ -3784,6 +3798,13 @@ void tst_qquicktextedit::largeTextObservesViewport()
textItem->setCursorPosition(cursorPos);
auto cursorRect = textItem->cursorRectangle();
textItem->setY(-cursorRect.top());
+ if (lcTests().isDebugEnabled())
+ QTest::qWait(500);
+ if (scrollDelta) {
+ textItem->setY(textItem->y() + scrollDelta);
+ if (lcTests().isDebugEnabled())
+ QTest::qWait(500);
+ }
qCDebug(lcTests) << "text size" << textItem->text().size() << "lines" << textItem->lineCount() << "font" << textItem->font();
Q_ASSERT(textItem->text().size() > QQuickTextEditPrivate::largeTextSizeThreshold);
QVERIFY(textItem->flags().testFlag(QQuickItem::ItemObservesViewport)); // large text sets this flag automatically
@@ -3793,11 +3814,10 @@ void tst_qquicktextedit::largeTextObservesViewport()
<< "expected" << expectedBlocksAboveViewport
<< "first block past viewport" << textPriv->firstBlockPastViewport
<< "expected" << expectedBlocksPastViewport
- << "region" << textPriv->renderedRegion
+ << "region" << textPriv->renderedRegion << "bottom" << textPriv->renderedRegion.bottom()
<< "expected range" << expectedRenderedRegionMin << expectedRenderedRegionMax;
- if (lcTests().isDebugEnabled())
- QTest::qWait(1000);
- QVERIFY(qAbs(textPriv->firstBlockInViewport - expectedBlocksAboveViewport) < expectedBlockTolerance);
+ if (scrollDelta >= 0) // unfortunately firstBlockInViewport isn't always reliable after scrolling
+ QTRY_VERIFY(qAbs(textPriv->firstBlockInViewport - expectedBlocksAboveViewport) < expectedBlockTolerance);
QVERIFY(qAbs(textPriv->firstBlockPastViewport - expectedBlocksPastViewport) < expectedBlockTolerance);
QVERIFY(textPriv->renderedRegion.top() > expectedRenderedRegionMin);
QVERIFY(textPriv->renderedRegion.bottom() < expectedRenderedRegionMax);