From 65ef4bab4ad0ef4a45ff56de3e143a588deac364 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Wed, 14 Jun 2017 13:15:45 +0200 Subject: QQuickText: don't clear the text formats on every layout In order to fix QTBUG-21919, 6ff9ba0 added a QTextLayout::clearFormats() call to QQuickTextPrivate::updateLayout(). This patch moves that logic to clearFormats(), called from setText() and setTextFormat() in order to avoid clearing the formats on every text layout update. This allows Qt Quick Controls 2 to extend QQuickText with support for mnenonics by adding a text format range to underline the appropriate piece of text in the internal QTextLayout. Task-number: QTBUG-61422 Change-Id: I646d53f0feeeaa3c106db94f187c7accabdc6a61 Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/quick/items/qquicktext.cpp | 15 +++++-- src/quick/items/qquicktext_p_p.h | 1 + tests/auto/quick/qquicktext/tst_qquicktext.cpp | 55 ++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 4 deletions(-) diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp index 1bcfbd41f7..2e66367e85 100644 --- a/src/quick/items/qquicktext.cpp +++ b/src/quick/items/qquicktext.cpp @@ -269,9 +269,6 @@ void QQuickTextPrivate::updateLayout() formatModifiesFontSize = fontSizeModified; multilengthEos = -1; } else { - layout.clearFormats(); - if (elideLayout) - elideLayout->clearFormats(); QString tmp = text; multilengthEos = tmp.indexOf(QLatin1Char('\x9c')); if (multilengthEos != -1) @@ -632,6 +629,13 @@ QString QQuickTextPrivate::elidedText(qreal lineWidth, const QTextLine &line, QT } } +void QQuickTextPrivate::clearFormats() +{ + layout.clearFormats(); + if (elideLayout) + elideLayout->clearFormats(); +} + /*! Lays out the QQuickTextPrivate::layout QTextLayout in the constraints of the QQuickText. @@ -1060,7 +1064,8 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const baseline) elideLayout = new QTextLayout; elideLayout->setCacheEnabled(true); } - if (styledText) { + QTextEngine *engine = layout.engine(); + if (engine && engine->hasFormats()) { QVector formats; switch (elideMode) { case QQuickText::ElideRight: @@ -1612,6 +1617,7 @@ void QQuickText::setText(const QString &n) d->extra->doc->setText(n); d->rightToLeftText = d->extra->doc->toPlainText().isRightToLeft(); } else { + d->clearFormats(); d->rightToLeftText = d->text.isRightToLeft(); } d->determineHorizontalAlignment(); @@ -2102,6 +2108,7 @@ void QQuickText::setTextFormat(TextFormat format) d->extra->doc->setText(d->text); d->rightToLeftText = d->extra->doc->toPlainText().isRightToLeft(); } else { + d->clearFormats(); d->rightToLeftText = d->text.isRightToLeft(); d->textHasChanged = true; } diff --git a/src/quick/items/qquicktext_p_p.h b/src/quick/items/qquicktext_p_p.h index fde07eaf2e..957641ec0a 100644 --- a/src/quick/items/qquicktext_p_p.h +++ b/src/quick/items/qquicktext_p_p.h @@ -85,6 +85,7 @@ public: int lineHeightOffset() const; QString elidedText(qreal lineWidth, const QTextLine &line, QTextLine *nextLine = 0) const; void elideFormats(int start, int length, int offset, QVector *elidedFormats); + void clearFormats(); void processHoverEvent(QHoverEvent *event); diff --git a/tests/auto/quick/qquicktext/tst_qquicktext.cpp b/tests/auto/quick/qquicktext/tst_qquicktext.cpp index c5fa0e19fa..4e643bb9d9 100644 --- a/tests/auto/quick/qquicktext/tst_qquicktext.cpp +++ b/tests/auto/quick/qquicktext/tst_qquicktext.cpp @@ -723,6 +723,61 @@ void tst_qquicktext::textFormat() QCOMPARE(text->textFormat(), QQuickText::AutoText); QCOMPARE(spy.count(), 2); } + + { + QQmlComponent component(&engine); + component.setData("import QtQuick 2.0\n Text { text: \"Hello\" }", QUrl()); + QScopedPointer object(component.create()); + QQuickText *text = qobject_cast(object.data()); + QVERIFY(text); + QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(text); + QVERIFY(textPrivate); + + QCOMPARE(text->textFormat(), QQuickText::AutoText); + QVERIFY(!textPrivate->layout.formats().isEmpty()); + + text->setTextFormat(QQuickText::StyledText); + QVERIFY(!textPrivate->layout.formats().isEmpty()); + + text->setTextFormat(QQuickText::PlainText); + QVERIFY(textPrivate->layout.formats().isEmpty()); + + text->setTextFormat(QQuickText::AutoText); + QVERIFY(!textPrivate->layout.formats().isEmpty()); + } + + { + QQmlComponent component(&engine); + component.setData("import QtQuick 2.0\nText { text: \"Hello\"; elide: Text.ElideRight }", QUrl::fromLocalFile("")); + QScopedPointer object(component.create()); + QQuickText *text = qobject_cast(object.data()); + QVERIFY(text); + QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(text); + QVERIFY(textPrivate); + + // underline a mnemonic + QVector formats; + QTextLayout::FormatRange range; + range.start = 0; + range.length = 1; + range.format.setFontUnderline(true); + formats << range; + + // the mnemonic format should be retained + textPrivate->layout.setFormats(formats); + text->forceLayout(); + QCOMPARE(textPrivate->layout.formats(), formats); + + // and carried over to the elide layout + text->setWidth(text->implicitWidth() - 1); + QVERIFY(textPrivate->elideLayout); + QCOMPARE(textPrivate->elideLayout->formats(), formats); + + // but cleared when the text changes + text->setText("Changed"); + QVERIFY(textPrivate->elideLayout); + QVERIFY(textPrivate->layout.formats().isEmpty()); + } } //the alignment tests may be trivial o.oa -- cgit v1.2.3