/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #ifdef Q_OS_DARWIN #include #include #include #include #include #endif static int s_mode; static QString s_text = QString::fromUtf8("The quick brown \xF0\x9F\xA6\x8A jumps over the lazy \xF0\x9F\x90\xB6"); class TextRenderer : public QWidget { Q_OBJECT public: enum RenderingMode { QtRendering, NativeRendering }; Q_ENUM(RenderingMode); TextRenderer(qreal pointSize, const QString &text, const QColor &textColor = QColor(), const QColor &bgColor = QColor()) : m_text(text) { if (pointSize) { QFont f = font(); f.setPointSize(pointSize); setFont(f); } if (textColor.isValid()) { QPalette p = palette(); p.setColor(QPalette::Text, textColor); setPalette(p); } if (bgColor.isValid()) { QPalette p = palette(); p.setColor(QPalette::Window, bgColor); setPalette(p); } } QString text() const { return !m_text.isNull() ? m_text : s_text; } QSize sizeHint() const override { QFontMetrics fm = fontMetrics(); return QSize(fm.boundingRect(text()).width(), fm.height()); } bool event(QEvent * event) override { if (event->type() == QEvent::ToolTip) { QString toolTip; QDebug debug(&toolTip); debug << "textColor =" << palette().color(QPalette::Text) << "bgColor =" << palette().color(QPalette::Window); setToolTip(toolTip); } return QWidget::event(event); } void paintEvent(QPaintEvent *) override { QImage image(size() * devicePixelRatio(), QImage::Format_ARGB32_Premultiplied); image.setDevicePixelRatio(devicePixelRatio()); QPainter p(&image); p.fillRect(QRect(0, 0, image.width(), image.height()), palette().window().color()); const int ascent = fontMetrics().ascent(); QPen metricsPen(QColor(112, 216, 255), 1.0); metricsPen.setCosmetic(true); p.setPen(metricsPen); p.drawLine(QPoint(0, ascent), QPoint(width(), ascent)); p.end(); if (s_mode == QtRendering) renderQtText(image); else renderNativeText(image); QPainter wp(this); wp.drawImage(QPoint(0, 0), image); } void renderQtText(QImage &image) { QPainter p(&image); const int ascent = fontMetrics().ascent(); p.setPen(palette().text().color()); QFont f = font(); f.setResolveMask(-1); p.setFont(f); p.drawText(QPoint(0, ascent), text()); } void renderNativeText(QImage &image) { #ifdef Q_OS_DARWIN QMacAutoReleasePool pool; QMacCGContext ctx(&image); const auto *fontEngine = QFontPrivate::get(font())->engineForScript(QChar::Script_Common); Q_ASSERT(fontEngine); if (fontEngine->type() == QFontEngine::Multi) { fontEngine = static_cast(fontEngine)->engine(0); Q_ASSERT(fontEngine); } Q_ASSERT(fontEngine->type() == QFontEngine::Mac); QColor textColor = palette().text().color(); auto nsColor = [NSColor colorWithSRGBRed:textColor.redF() green:textColor.greenF() blue:textColor.blueF() alpha:textColor.alphaF()]; if (font().styleStrategy() & QFont::NoAntialias) CGContextSetShouldAntialias(ctx, false); // Flip to what CT expects CGContextScaleCTM(ctx, 1, -1); CGContextTranslateCTM(ctx, 0, -height()); // Set up baseline CGContextSetTextPosition(ctx, 0, height() - fontMetrics().ascent()); auto *attributedString = [[NSAttributedString alloc] initWithString:text().toNSString() attributes:@{ NSFontAttributeName : (NSFont *)fontEngine->handle(), NSForegroundColorAttributeName : nsColor } ]; QCFType line = CTLineCreateWithAttributedString(CFAttributedStringRef([attributedString autorelease])); CTLineDraw(line, ctx); #endif } public: RenderingMode m_mode = QtRendering; QString m_text; }; class TestWidget : public QWidget { Q_OBJECT public: TestWidget() { auto *mainLayout = new QVBoxLayout; m_previews = new QWidget; m_previews->setLayout(new QHBoxLayout); for (int i = 0; i < 6; ++i) { auto *layout = new QVBoxLayout; QString text; if (i > 0) text = "ABC"; QPair color = [i] { switch (i) { case 0: return qMakePair(QColor(), QColor()); case 1: return qMakePair(QColor(Qt::black), QColor(Qt::white)); case 2: return qMakePair(QColor(Qt::white), QColor(Qt::black)); case 3: return qMakePair(QColor(Qt::magenta), QColor(Qt::green)); case 4: return qMakePair(QColor(0, 0, 0, 128), QColor(Qt::white)); case 5: return qMakePair(QColor(255, 255, 255, 128), QColor(Qt::black)); default: return qMakePair(QColor(), QColor()); } }(); for (int pointSize : {8, 12, 24, 36, 48}) layout->addWidget(new TextRenderer(pointSize, text, color.first, color.second)); static_cast(m_previews->layout())->addLayout(layout); } mainLayout->addWidget(m_previews); auto *controls = new QHBoxLayout; auto *lineEdit = new QLineEdit(s_text); connect(lineEdit, &QLineEdit::textChanged, [&](const QString &text) { s_text = text; for (TextRenderer *renderer : m_previews->findChildren()) renderer->updateGeometry(); }); controls->addWidget(lineEdit); auto *colorButton = new QPushButton("Color..."); connect(colorButton, &QPushButton::clicked, [&] { auto *colorDialog = new QColorDialog(this); colorDialog->setOptions(QColorDialog::NoButtons | QColorDialog::ShowAlphaChannel); colorDialog->setModal(false); connect(colorDialog, &QColorDialog::currentColorChanged, [&](const QColor &color) { QPalette p = palette(); p.setColor(QPalette::Text, color); setPalette(p); }); colorDialog->setCurrentColor(palette().text().color()); colorDialog->setVisible(true); }); controls->addWidget(colorButton); auto *fontButton = new QPushButton("Font..."); connect(fontButton, &QPushButton::clicked, [&] { auto *fontDialog = new QFontDialog(this); fontDialog->setOptions(QFontDialog::NoButtons); fontDialog->setModal(false); fontDialog->setCurrentFont(m_previews->font()); connect(fontDialog, &QFontDialog::currentFontChanged, [&](const QFont &font) { m_previews->setFont(font); }); fontDialog->setVisible(true); }); controls->addWidget(fontButton); auto *aaButton = new QCheckBox("NoAntialias"); connect(aaButton, &QCheckBox::stateChanged, [&] { for (TextRenderer *renderer : m_previews->findChildren()) { QFont font = renderer->font(); font.setStyleStrategy(QFont::StyleStrategy(font.styleStrategy() ^ QFont::NoAntialias)); renderer->setFont(font); } }); controls->addWidget(aaButton); auto *subpixelAAButton = new QCheckBox("NoSubpixelAntialias"); connect(subpixelAAButton, &QCheckBox::stateChanged, [&] { for (TextRenderer *renderer : m_previews->findChildren()) { QFont font = renderer->font(); font.setStyleStrategy(QFont::StyleStrategy(font.styleStrategy() ^ QFont::NoSubpixelAntialias)); renderer->setFont(font); } }); controls->addWidget(subpixelAAButton); controls->addStretch(); mainLayout->addLayout(controls); mainLayout->setSizeConstraint(QLayout::SetFixedSize); setLayout(mainLayout); setMode(TextRenderer::QtRendering); setFocusPolicy(Qt::StrongFocus); setFocus(); } void setMode(TextRenderer::RenderingMode mode) { s_mode = mode; setWindowTitle(s_mode == TextRenderer::QtRendering ? "Qt" : "Native"); for (TextRenderer *renderer : m_previews->findChildren()) renderer->update(); } void mousePressEvent(QMouseEvent *) override { setMode(TextRenderer::RenderingMode(!s_mode)); } void keyPressEvent(QKeyEvent *e) override { if (e->key() == Qt::Key_Space) setMode(TextRenderer::RenderingMode(!s_mode)); } QWidget *m_previews; }; int main(int argc, char **argv) { qputenv("QT_MAX_CACHED_GLYPH_SIZE", "97"); QApplication app(argc, argv); TestWidget widget; widget.show(); return app.exec(); } #include "main.moc"