// Copyright (C) 2020 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #undef QT_NO_FOREACH // this file contains unported legacy Q_FOREACH uses #include #include #include #include #include #include #include static const int lastMeasurementsCount = 50; class FontBlaster: public QWidget { Q_OBJECT public: FontBlaster(QWidget *parent = nullptr) : QWidget(parent) , m_currentMode(0) { setFocusPolicy(Qt::StrongFocus); } void paintEvent(QPaintEvent *event) { Q_UNUSED(event); QPainter p(this); if (m_timer.isValid()) m_lastMeasurements.append(m_timer.elapsed()); m_timer.start(); p.save(); m_modes[m_currentMode].function(p, size()); p.restore(); const QFontMetrics fm = p.fontMetrics(); p.setOpacity(0.7); p.fillRect(0, 0, width(), fm.height(), Qt::gray); p.fillRect(0, height() - fm.height(), width(), height(), Qt::gray); p.setOpacity(1); p.setPen(palette().color(QPalette::Text)); p.drawText(2, fm.ascent(), m_modes[m_currentMode].name); if (m_lastMeasurements.count() == lastMeasurementsCount) { m_lastMeasurements.removeFirst(); int lastMsecsSum = 0; foreach(const int measurement, m_lastMeasurements) lastMsecsSum += measurement; p.drawText(2, height() - fm.descent(), QLatin1String("Fps: ") + QString::number(1000 / ((qreal)lastMsecsSum / lastMeasurementsCount), 'f', 1) ); } QTimer::singleShot(0, this, SLOT(repaint())); } /* Creating all kinds of size/weight/italic combinations, stress testing the glyph cache. Also: painting with different opacities, stress testing blitting. */ static void paintDifferentFontStyles(QPainter &p, const QSize &size) { static const QString text = QLatin1String("Qt rocks!!!"); static const int textsPerPaint = 30; for (int i = 0; i < textsPerPaint; i++) { const int fontSize = 4 + QRandomGenerator::global()->bounded(5); const int fontWeight = QRandomGenerator::global()->bounded(2) == 1 ? QFont::Normal : QFont::Bold; const bool fontItalic = QRandomGenerator::global()->bounded(2) == 1; const QFont font("Default", fontSize, fontWeight, fontItalic); p.setFont(font); p.setPen(QColor::fromHsv(QRandomGenerator::global()->bounded(359), 155 + QRandomGenerator::global()->bounded(100), 155 + QRandomGenerator::global()->bounded(100), 100 + QRandomGenerator::global()->bounded(155))); const QSize textSize(p.fontMetrics().boundingRect(text).size()); const QPoint position( -textSize.width() / 2 + QRandomGenerator::global()->bounded(size.width()), textSize.height() / 2 + QRandomGenerator::global()->bounded(size.height())); p.drawText(position, text); } } /* Drawing a multiline latin text, stress testing the text layout system. */ static void paintLongLatinText(QPainter &p, const QSize &size) { static const char* const pieces[] = { "lorem ipsum", "dolor sit amet", "consectetuer", "sed diam nonumy", "eos et accusam", "sea takimata sanctus" }; static const int piecesCount = (int)(sizeof pieces / sizeof pieces[0]); static const int piecesPerPaint = 30; QString text; for (int i = 0; i < piecesPerPaint; ++i) { QString piece = QLatin1String(pieces[QRandomGenerator::global()->bounded(piecesCount)]); if (i == 0 || QRandomGenerator::global()->bounded(2)) { // Make this piece the beginning of a new sentence. piece[0] = piece[0].toUpper(); if (i > 0) piece.prepend(QLatin1String(". ")); } else { piece.prepend(QLatin1String(", ")); } text.append(piece); } text.append(QLatin1Char('.')); p.drawText(QRectF(QPointF(0, 0), QSizeF(size)), Qt::AlignTop | Qt::AlignAbsolute | Qt::TextWordWrap, text); } /* Drawing one text with several snippets of different writingSystems, stress testing the font merging in the font database. */ static void paintInternationalText(QPainter &p, const QSize &size) { static QStringList samples; if (samples.isEmpty()) { foreach (const QFontDatabase::WritingSystem system, QFontDatabase::writingSystems()) if (system != QFontDatabase::Ogham && system != QFontDatabase::Runic) samples.append(QFontDatabase::writingSystemSample(system)); } static const int systemsPerPaint = 65; QString text; for (int i = 0; i < systemsPerPaint; i++) { if (i > 0) text.append(QLatin1Char(' ')); text.append(samples.at(QRandomGenerator::global()->bounded(samples.count()))); } p.drawText(QRectF(QPointF(0, 0), QSizeF(size)), Qt::AlignTop | Qt::AlignAbsolute | Qt::TextWordWrap, text); } protected: void nextMode() { m_currentMode = (m_currentMode + 1) % m_modesCount; m_lastMeasurements.clear(); } void keyPressEvent(QKeyEvent *event) { Q_UNUSED(event); nextMode(); } void mousePressEvent(QMouseEvent *event) { Q_UNUSED(event); nextMode(); } private: static const struct mode { QString name; void (*function)(QPainter &, const QSize&); } m_modes[]; static const int m_modesCount; int m_currentMode; QList m_lastMeasurements; QElapsedTimer m_timer; }; const struct FontBlaster::mode FontBlaster::m_modes[] = { { QLatin1String("Qt rocks!!!"), FontBlaster::paintDifferentFontStyles }, { QLatin1String("Latin"), FontBlaster::paintLongLatinText }, { QLatin1String("International"), FontBlaster::paintInternationalText } }; const int FontBlaster::m_modesCount = (int)(sizeof m_modes / sizeof m_modes[0]); int main(int argc, char *argv[]) { QApplication a(argc, argv); FontBlaster dlg; dlg.show(); return a.exec(); } #include "main.moc"