summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPierre Rossi <pierre.rossi@digia.com>2012-02-10 20:42:13 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2012-10-08 17:22:56 +0200
commit101d04681f4ceb7410681eae684534a206a9d90a (patch)
treebb037f84ac82fc9431a72ed7ec9ecdff18ddef7c
parent0e8a2788d84c814b698848b699af8a2c8ba3179f (diff)
Handle additional format ranges when itemizing.
This is useful when the additional formats are used on a text layout using a raw font. It can also come in handy for input methods operating on a QTextDocument. We now consider all format range edges to generate the associated items. The capitalization can be overridden via the additionnal formats mechanism. Adds an autotest that checks that this works with font capitalization. Change-Id: I782d2c48d05b0dfbad480a9ca77198465292b358 Reviewed-by: Konstantin Ritt <ritt.ks@gmail.com>
-rw-r--r--src/gui/text/qtextengine.cpp63
-rw-r--r--tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp108
-rw-r--r--tests/auto/widgets/widgets/qtextedit/tst_qtextedit.cpp7
-rw-r--r--tests/benchmarks/gui/text/qtext/main.cpp2
4 files changed, 153 insertions, 27 deletions
diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp
index 8527a85369..d5f086a670 100644
--- a/src/gui/text/qtextengine.cpp
+++ b/src/gui/text/qtextengine.cpp
@@ -55,6 +55,7 @@
#include "qtextdocument_p.h"
#include "qrawfont.h"
#include "qrawfont_p.h"
+#include <qbitarray.h>
#include <qguiapplication.h>
#include <qinputmethod.h>
#include <algorithm>
@@ -87,7 +88,7 @@ public:
/// The caps parameter is used to choose the algoritm of splitting text and assiging roles to the textitems
void generate(int start, int length, QFont::Capitalization caps)
{
- if ((int)caps == (int)QFont::SmallCaps)
+ if (caps == QFont::SmallCaps)
generateScriptItemsSmallCaps(reinterpret_cast<const ushort *>(m_string.unicode()), start, length);
else if(caps == QFont::Capitalize)
generateScriptItemsCapitalize(start, length);
@@ -1381,6 +1382,13 @@ void QTextEngine::itemize() const
Itemizer itemizer(layoutData->string, scriptAnalysis.data(), layoutData->items);
+ QVarLengthArray<uchar, 128> capitalization;
+ if (formats()) {
+ capitalization.resize(length);
+ memset(capitalization.data(), formats()->defaultFont().capitalization(), length);
+ }
+ QBitArray edges(length+1); // First and last bit are not really used but this makes things simpler.
+
const QTextDocumentPrivate *p = block.docHandle();
if (p) {
SpecialData *s = specialData;
@@ -1399,14 +1407,12 @@ void QTextEngine::itemize() const
s = 0;
}
Q_ASSERT(position <= length);
- QFont::Capitalization capitalization =
- formats()->charFormat(format).hasProperty(QTextFormat::FontCapitalization)
- ? formats()->charFormat(format).fontCapitalization()
- : formats()->defaultFont().capitalization();
- itemizer.generate(prevPosition, position - prevPosition, capitalization);
+ if (formats()->charFormat(format).hasProperty(QTextFormat::FontCapitalization))
+ memset(capitalization.data() + prevPosition, formats()->charFormat(format).fontCapitalization(), position - prevPosition);
+ edges.setBit(position);
if (it == end) {
- if (position < length)
- itemizer.generate(position, length - position, capitalization);
+ if (position < length && formats()->charFormat(format).hasProperty(QTextFormat::FontCapitalization))
+ memset(capitalization.data() + position, formats()->charFormat(format).fontCapitalization(), length - position);
break;
}
format = frag->format;
@@ -1415,22 +1421,33 @@ void QTextEngine::itemize() const
position += frag->size_array[0];
++it;
}
- } else {
-#ifndef QT_NO_RAWFONT
- if (useRawFont && specialData) {
- int lastIndex = 0;
- for (int i = 0; i < specialData->addFormats.size(); ++i) {
+ }
+
+ if (specialData && !specialData->addFormats.isEmpty()) {
+ Q_ASSERT(formats());
+ for (int i = 0; i < specialData->addFormats.size(); ++i) {
const QTextLayout::FormatRange &range = specialData->addFormats.at(i);
- if (range.format.fontCapitalization()) {
- itemizer.generate(lastIndex, range.start - lastIndex, QFont::MixedCase);
- itemizer.generate(range.start, range.length, range.format.fontCapitalization());
- lastIndex = range.start + range.length;
- }
- }
- itemizer.generate(lastIndex, length - lastIndex, QFont::MixedCase);
- } else
-#endif
- itemizer.generate(0, length, static_cast<QFont::Capitalization> (fnt.d->capital));
+ Q_ASSERT(range.start + range.length <= length);
+ edges.setBit(range.start);
+ edges.setBit(range.start + range.length);
+ QTextCharFormat format = formats()->charFormat(specialData->addFormatIndices.at(i));
+ if (format.hasProperty(QTextFormat::FontCapitalization))
+ memset(capitalization.data() + range.start, format.fontCapitalization(), range.length);
+ }
+ }
+
+ if (formats()) {
+ int previousBoundary = 0;
+ for (int i = 1; i < length; ++i) {
+ if (!edges.at(i))
+ continue;
+ itemizer.generate(previousBoundary, i - previousBoundary, static_cast<QFont::Capitalization>(capitalization[previousBoundary]));
+ previousBoundary = i;
+ }
+ itemizer.generate(previousBoundary, length - previousBoundary, static_cast<QFont::Capitalization>(capitalization[previousBoundary]));
+
+ } else {
+ itemizer.generate(0, length, static_cast<QFont::Capitalization> (fnt.d->capital));
}
addRequiredBoundaries();
diff --git a/tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp b/tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp
index 77f603af4f..2f8fab9e64 100644
--- a/tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp
+++ b/tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp
@@ -139,6 +139,11 @@ private slots:
void xToCursorForLigatures();
void cursorInNonStopChars();
+#ifndef QT_NO_RAWFONT
+ void additionalFormatsCapitalizationWithRawFont_data();
+ void additionalFormatsCapitalizationWithRawFont();
+#endif
+
private:
QFont testFont;
};
@@ -2012,5 +2017,108 @@ void tst_QTextLayout::cursorInNonStopChars()
QVERIFY(line.cursorToX(2) == line.cursorToX(3));
}
+#ifndef QT_NO_RAWFONT
+
+typedef QList<QTextLayout::FormatRange> FormatRangeList;
+Q_DECLARE_METATYPE(FormatRangeList)
+
+void tst_QTextLayout::additionalFormatsCapitalizationWithRawFont_data()
+{
+ QTest::addColumn<QString>("text");
+ QTest::addColumn<FormatRangeList>("additionalFormats");
+
+ QString textSample = QLatin1String("Code Less, Create More.");
+
+ QTest::newRow("No Format") << textSample << FormatRangeList();
+ QTextLayout::FormatRange range;
+ range.start = 0;
+ range.length = textSample.size();
+ range.format.setFontCapitalization(QFont::SmallCaps);
+ QTest::newRow("SmallCaps") << textSample << (FormatRangeList() << range);
+ range.format.setFontCapitalization(QFont::Capitalize);
+ QTest::newRow("Capitalize") << textSample.toLower() << (FormatRangeList() << range);
+ range.format.setFontCapitalization(QFont::AllLowercase);
+ QTest::newRow("AllLowercase") << textSample << (FormatRangeList() << range);
+
+ FormatRangeList rangeList;
+ range.start = 0;
+ range.length = 5;
+ range.format.setFontCapitalization(QFont::SmallCaps);
+ rangeList << range;
+ range.start = 5;
+ range.format.setFontCapitalization(QFont::AllLowercase);
+ rangeList << range;
+ range.start = 18;
+ range.format.setFontCapitalization(QFont::Capitalize);
+ rangeList << range;
+ QTest::newRow("MixAndMatch") << textSample << rangeList;
+}
+
+void tst_QTextLayout::additionalFormatsCapitalizationWithRawFont()
+{
+ QFETCH(QString, text);
+ QFETCH(FormatRangeList, additionalFormats);
+
+ QRawFont rawFont = QRawFont::fromFont(testFont);
+
+ QTextLayout layout(text);
+ layout.setRawFont(rawFont);
+ layout.setAdditionalFormats(additionalFormats);
+ layout.beginLayout();
+ layout.createLine();
+ layout.endLayout();
+
+ QString expectedChars;
+ QTextBoundaryFinder splitter(QTextBoundaryFinder::Word,text.constData(), text.length(), 0, 0);
+
+ for (int i = 0; i < text.size(); ++i) {
+ bool hasFormat = false;
+ Q_FOREACH (const QTextLayout::FormatRange& range, additionalFormats) {
+ if (i >= range.start && i < range.start + range.length) {
+ hasFormat = true;
+ const QChar ch(text.at(i));
+ switch (range.format.fontCapitalization()) {
+ case QFont::SmallCaps:
+ case QFont::AllUppercase:
+ expectedChars += ch.toUpper();
+ break;
+ case QFont::AllLowercase:
+ expectedChars += ch.toLower();
+ break;
+ case QFont::Capitalize:
+ splitter.setPosition(i);
+ if (splitter.boundaryReasons() & QTextBoundaryFinder::StartWord)
+ expectedChars += ch.toUpper();
+ else
+ expectedChars += ch;
+ break;
+ case QFont::MixedCase:
+ default:
+ expectedChars += ch;
+ break;
+ }
+ }
+ }
+ if (!hasFormat)
+ expectedChars += text.at(i);
+ }
+
+ QVERIFY(layout.glyphRuns().size() > 0);
+ rawFont = layout.glyphRuns().first().rawFont();
+ // Can't assume anything about the order of the glyphs we get once they're split into several glyphRuns.
+ // Let's just compare the sets:
+ QVector<quint32> expected = rawFont.glyphIndexesForString(expectedChars);
+ qSort(expected);
+ QVector<quint32> sortedOutput;
+ sortedOutput.reserve(expected.size());
+ Q_FOREACH (const QGlyphRun& run, layout.glyphRuns()) {
+ Q_FOREACH (quint32 glyphIndex, run.glyphIndexes())
+ sortedOutput.append(glyphIndex);
+ }
+ qSort(sortedOutput);
+ QCOMPARE(sortedOutput, expected);
+}
+#endif
+
QTEST_MAIN(tst_QTextLayout)
#include "tst_qtextlayout.moc"
diff --git a/tests/auto/widgets/widgets/qtextedit/tst_qtextedit.cpp b/tests/auto/widgets/widgets/qtextedit/tst_qtextedit.cpp
index 27369adc22..bc414f5b19 100644
--- a/tests/auto/widgets/widgets/qtextedit/tst_qtextedit.cpp
+++ b/tests/auto/widgets/widgets/qtextedit/tst_qtextedit.cpp
@@ -2473,10 +2473,11 @@ void tst_QTextEdit::highlightLongLine()
edit.setAcceptRichText(false);
edit.setWordWrapMode(QTextOption::NoWrap);
- QString singeLongLine;
+ QString singleLongLine;
+ singleLongLine.reserve(100000);
for (int i = 0; i < 10000; ++i)
- singeLongLine += "0123456789";
- edit.setPlainText(singeLongLine);
+ singleLongLine += "0123456789";
+ edit.setPlainText(singleLongLine);
class NumHighlighter : public QSyntaxHighlighter {
public:
diff --git a/tests/benchmarks/gui/text/qtext/main.cpp b/tests/benchmarks/gui/text/qtext/main.cpp
index 543b9041da..c9d5d59891 100644
--- a/tests/benchmarks/gui/text/qtext/main.cpp
+++ b/tests/benchmarks/gui/text/qtext/main.cpp
@@ -362,7 +362,7 @@ void tst_QText::formattedLayout_data()
ranges.append(formatRange);
}
- QTest::newRow("long-many") << m_shortLorem << ranges;
+ QTest::newRow("long-many") << text << ranges;
}
}