Fix invalid text layout data when a full layout run is interrupted

When a QTextDocument is laid out, this is done in "chunks" to keep
programs responsive. During the layout process, blocks are split into
lines. When a full (re)layout is interrupted (e.g. because a
QHighlighter changes some formats before the layout for all chunks is
completed), later chunks are skipped. This results in invalid data
(e.g., blocks not split into lines).
This change ensures that full layout runs of the root frame are
completed even after interruptions.

Fixes: QTBUG-20354
Change-Id: I041c73a532a5abe74d577ca49810191b5594dca2
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
This commit is contained in:
Stefan Löffler 2020-04-26 12:03:28 +02:00
parent 844967d297
commit 09ee4282e5

View File

@ -105,13 +105,14 @@ public:
bool sizeDirty; bool sizeDirty;
bool layoutDirty; bool layoutDirty;
bool fullLayoutCompleted;
QVector<QPointer<QTextFrame> > floats; QVector<QPointer<QTextFrame> > floats;
}; };
QTextFrameData::QTextFrameData() QTextFrameData::QTextFrameData()
: maximumWidth(QFIXED_MAX), : maximumWidth(QFIXED_MAX),
currentLayoutStruct(nullptr), sizeDirty(true), layoutDirty(true) currentLayoutStruct(nullptr), sizeDirty(true), layoutDirty(true), fullLayoutCompleted(false)
{ {
} }
@ -2943,7 +2944,7 @@ QRectF QTextDocumentLayoutPrivate::layoutFrame(QTextFrame *f, int layoutFrom, in
QTextFrameData *fd = data(f); QTextFrameData *fd = data(f);
QFixed newContentsWidth; QFixed newContentsWidth;
bool fullLayout = false; bool fullLayout = (f == document->rootFrame() && !fd->fullLayoutCompleted);
{ {
QTextFrameFormat fformat = f->frameFormat(); QTextFrameFormat fformat = f->frameFormat();
// set sizes of this frame from the format // set sizes of this frame from the format
@ -3397,6 +3398,7 @@ void QTextDocumentLayoutPrivate::layoutFlow(QTextFrame::Iterator it, QTextLayout
cp.contentsWidth = layoutStruct->contentsWidth; cp.contentsWidth = layoutStruct->contentsWidth;
checkPoints.append(cp); checkPoints.append(cp);
checkPoints.reserve(checkPoints.size()); checkPoints.reserve(checkPoints.size());
fd->fullLayoutCompleted = true;
} else { } else {
currentLazyLayoutPosition = checkPoints.constLast().positionInFrame; currentLazyLayoutPosition = checkPoints.constLast().positionInFrame;
// ####### // #######
@ -3808,6 +3810,7 @@ void QTextDocumentLayout::documentChanged(int from, int oldLength, int length)
d->contentHasAlignment = false; d->contentHasAlignment = false;
d->currentLazyLayoutPosition = 0; d->currentLazyLayoutPosition = 0;
d->checkPoints.clear(); d->checkPoints.clear();
data(d->docPrivate->rootFrame())->fullLayoutCompleted = false;
d->layoutStep(); d->layoutStep();
} else { } else {
d->ensureLayoutedByPosition(from); d->ensureLayoutedByPosition(from);