File indexing completed on 2024-04-28 05:50:51
0001 /* 0002 SPDX-FileCopyrightText: 2020-2020 Gustavo Carneiro <gcarneiroa@hotmail.com> 0003 SPDX-FileCopyrightText: 2007-2008 Robert Knight <robertknight@gmail.com> 0004 SPDX-FileCopyrightText: 1997, 1998 Lars Doelle <lars.doelle@on-line.de> 0005 0006 SPDX-License-Identifier: GPL-2.0-or-later 0007 */ 0008 0009 // Own 0010 #include "TerminalFonts.h" 0011 0012 // Konsole 0013 #include "konsoledebug.h" 0014 #include "session/Session.h" 0015 #include "session/SessionController.h" 0016 #include "session/SessionManager.h" 0017 #include "terminalDisplay/TerminalDisplay.h" 0018 0019 // Qt 0020 #include <QFont> 0021 #include <QFontMetrics> 0022 0023 namespace Konsole 0024 { 0025 TerminalFont::TerminalFont(QWidget *parent) 0026 : m_parent(parent) 0027 { 0028 } 0029 0030 void TerminalFont::applyProfile(const Profile::Ptr &profile) 0031 { 0032 m_profile = profile; 0033 m_antialiasText = profile->antiAliasFonts(); 0034 m_boldIntense = profile->boldIntense(); 0035 m_useFontLineCharacters = profile->useFontLineCharacters(); 0036 m_lineSpacing = uint(profile->lineSpacing()); 0037 setVTFont(profile->font()); 0038 extraFonts[0] = profile->emojiFont(); 0039 if (extraFonts[0] == QFont()) { 0040 extraFonts[0] = QFont(QStringLiteral("Noto Color Emoji")); 0041 // extraFonts[0] = QFont(QStringLiteral("Apple Color Emoji")); 0042 // extraFonts[0] = QFont(QStringLiteral("Emoji One")); 0043 if (extraFonts[0] == QFont()) { 0044 extraFonts.remove(0); 0045 } 0046 } 0047 } 0048 0049 void TerminalFont::setVTFont(const QFont &f) 0050 { 0051 QFont newFont(f); 0052 int strategy = 0; 0053 0054 // hint that text should be drawn with- or without anti-aliasing. 0055 // depending on the user's font configuration, this may not be respected 0056 strategy |= m_antialiasText ? QFont::PreferAntialias : QFont::NoAntialias; 0057 0058 // In case the provided font doesn't have some specific characters it should 0059 // fall back to a Monospace fonts. 0060 newFont.setStyleHint(QFont::TypeWriter, QFont::StyleStrategy(strategy)); 0061 0062 // Try to check that a good font has been loaded. 0063 // For some fonts, ForceIntegerMetrics causes height() == 0 which 0064 // will cause Konsole to crash later. 0065 QFontMetrics fontMetrics2(newFont); 0066 if (fontMetrics2.height() < 1) { 0067 qCDebug(KonsoleDebug) << "The font " << newFont.toString() << " has an invalid height()"; 0068 // Ask for a generic font so at least it is usable. 0069 // Font listed in profile's dialog will not be updated. 0070 newFont = QFont(QStringLiteral("Monospace")); 0071 0072 newFont.setStyleHint(QFont::TypeWriter, QFont::StyleStrategy(strategy)); 0073 qCDebug(KonsoleDebug) << "Font changed to " << newFont.toString(); 0074 } 0075 0076 // experimental optimization. Konsole assumes that the terminal is using a 0077 // mono-spaced font, in which case kerning information should have an effect. 0078 // Disabling kerning saves some computation when rendering text. 0079 newFont.setKerning(false); 0080 0081 // QFont::ForceIntegerMetrics has been removed. 0082 // Set full hinting instead to ensure the letters are aligned properly. 0083 newFont.setHintingPreference(QFont::PreferFullHinting); 0084 0085 // "Draw intense colors in bold font" feature needs to use different font weights. StyleName 0086 // property, when set, doesn't allow weight changes. Since all properties (weight, stretch, 0087 // italic, etc) are stored in QFont independently, in almost all cases styleName is not needed. 0088 newFont.setStyleName(QString()); 0089 0090 if (newFont == qobject_cast<QWidget *>(m_parent)->font()) { 0091 // Do not process the same font again 0092 return; 0093 } 0094 0095 QFontInfo fontInfo(newFont); 0096 0097 // clang-format off 0098 // QFontInfo::fixedPitch() appears to not match QFont::fixedPitch() - do not test it. 0099 // related? https://bugreports.qt.io/browse/QTBUG-34082 0100 if (fontInfo.family() != newFont.family() 0101 || !qFuzzyCompare(fontInfo.pointSizeF(), newFont.pointSizeF()) 0102 || fontInfo.styleHint() != newFont.styleHint() 0103 || fontInfo.weight() != newFont.weight() 0104 || fontInfo.style() != newFont.style() 0105 || fontInfo.underline() != newFont.underline() 0106 || fontInfo.strikeOut() != newFont.strikeOut() 0107 ) { // clang-format on 0108 static const char format[] = "%s,%g,%d,%d,%d,%d,%d,%d,%d"; 0109 const QString nonMatching = QString::asprintf(format, 0110 qPrintable(fontInfo.family()), 0111 fontInfo.pointSizeF(), 0112 -1, // pixelSize is not used 0113 static_cast<int>(fontInfo.styleHint()), 0114 fontInfo.weight(), 0115 static_cast<int>(fontInfo.style()), 0116 static_cast<int>(fontInfo.underline()), 0117 static_cast<int>(fontInfo.strikeOut()), 0118 // Intentional newFont use - fixedPitch is bugged, see comment above 0119 static_cast<int>(newFont.fixedPitch())); 0120 qCDebug(KonsoleDebug) << "The font to use in the terminal can not be matched exactly on your system."; 0121 qCDebug(KonsoleDebug) << " Selected: " << newFont.toString(); 0122 qCDebug(KonsoleDebug) << " System : " << nonMatching; 0123 } 0124 0125 qobject_cast<QWidget *>(m_parent)->setFont(newFont); 0126 fontChange(newFont); 0127 } 0128 0129 QFont TerminalFont::getVTFont() const 0130 { 0131 return qobject_cast<QWidget *>(m_parent)->font(); 0132 } 0133 0134 void TerminalFont::increaseFontSize() 0135 { 0136 QFont font = qobject_cast<QWidget *>(m_parent)->font(); 0137 font.setPointSizeF(font.pointSizeF() + 1); 0138 setVTFont(font); 0139 } 0140 0141 void TerminalFont::decreaseFontSize() 0142 { 0143 const qreal MinimumFontSize = 6; 0144 0145 QFont font = qobject_cast<QWidget *>(m_parent)->font(); 0146 font.setPointSizeF(qMax(font.pointSizeF() - 1, MinimumFontSize)); 0147 setVTFont(font); 0148 } 0149 0150 void TerminalFont::resetFontSize() 0151 { 0152 const qreal MinimumFontSize = 6; 0153 0154 TerminalDisplay *display = qobject_cast<TerminalDisplay *>(m_parent); 0155 QFont font = display->font(); 0156 Profile::Ptr currentProfile = SessionManager::instance()->sessionProfile(display->sessionController()->session()); 0157 const qreal defaultFontSize = currentProfile->font().pointSizeF(); 0158 font.setPointSizeF(qMax(defaultFontSize, MinimumFontSize)); 0159 setVTFont(font); 0160 } 0161 0162 void TerminalFont::setLineSpacing(uint i) 0163 { 0164 m_lineSpacing = i; 0165 fontChange(qobject_cast<QWidget *>(m_parent)->font()); 0166 } 0167 0168 uint TerminalFont::lineSpacing() const 0169 { 0170 return m_lineSpacing; 0171 } 0172 0173 int TerminalFont::fontHeight() const 0174 { 0175 return m_fontHeight; 0176 } 0177 0178 int TerminalFont::fontWidth() const 0179 { 0180 return m_fontWidth; 0181 } 0182 0183 int TerminalFont::fontAscent() const 0184 { 0185 return m_fontAscent; 0186 } 0187 0188 int TerminalFont::lineWidth() const 0189 { 0190 return m_lineWidth; 0191 } 0192 0193 qreal TerminalFont::underlinePos() const 0194 { 0195 return m_underlinePos; 0196 } 0197 0198 int TerminalFont::strikeOutPos() const 0199 { 0200 return m_strikeOutPos; 0201 } 0202 0203 qreal TerminalFont::overlinePos() const 0204 { 0205 return m_overlinePos; 0206 } 0207 0208 bool TerminalFont::boldIntense() const 0209 { 0210 return m_boldIntense; 0211 } 0212 0213 bool TerminalFont::antialiasText() const 0214 { 0215 return m_antialiasText; 0216 } 0217 0218 bool TerminalFont::useFontLineCharacters() const 0219 { 0220 return m_useFontLineCharacters; 0221 } 0222 0223 void TerminalFont::fontChange(const QFont &) 0224 { 0225 QFontMetrics fm(qobject_cast<QWidget *>(m_parent)->font()); 0226 m_fontHeight = fm.height() + m_lineSpacing; 0227 0228 Q_ASSERT(m_fontHeight > 0); 0229 0230 m_fontWidth = fm.horizontalAdvance(QLatin1Char('M')); 0231 0232 if (m_fontWidth < 1) { 0233 m_fontWidth = 1; 0234 } 0235 0236 m_fontAscent = fm.ascent(); 0237 m_lineWidth = fm.lineWidth(); 0238 m_underlinePos = qMin(static_cast<qreal>(fm.underlinePos()), fm.descent() - m_lineWidth / static_cast<qreal>(2)); 0239 m_strikeOutPos = fm.strikeOutPos(); 0240 m_overlinePos = qMin(static_cast<qreal>(fm.overlinePos()), fm.ascent() - m_lineWidth / static_cast<qreal>(2)); 0241 0242 qobject_cast<TerminalDisplay *>(m_parent)->propagateSize(); 0243 } 0244 0245 bool TerminalFont::hasExtraFont(int i) const 0246 { 0247 return extraFonts.contains(i); 0248 } 0249 0250 QFont TerminalFont::getExtraFont(int i) const 0251 { 0252 return extraFonts[i]; 0253 } 0254 }