1// Copyright (C) 2019 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qfont.h"
5#include "qdebug.h"
6#include "qpaintdevice.h"
7#include "qfontdatabase.h"
8#include "qfontmetrics.h"
9#include "qfontinfo.h"
10#include "qpainter.h"
11#include "qhash.h"
12#include "qdatastream.h"
13#include "qguiapplication.h"
14#include "qstringlist.h"
15#include "qscreen.h"
16
17#include "qthread.h"
18#include "qthreadstorage.h"
19
20#include "qfont_p.h"
21#include <private/qfontengine_p.h>
22#include <private/qpainter_p.h>
23#include <private/qtextengine_p.h>
24#include <limits.h>
25
26#include <qpa/qplatformscreen.h>
27#include <qpa/qplatformintegration.h>
28#include <qpa/qplatformfontdatabase.h>
29#include <QtGui/private/qguiapplication_p.h>
30
31#include <QtCore/QMutexLocker>
32#include <QtCore/QMutex>
33
34#include <array>
35
36// #define QFONTCACHE_DEBUG
37#ifdef QFONTCACHE_DEBUG
38# define FC_DEBUG qDebug
39#else
40# define FC_DEBUG if (false) qDebug
41#endif
42
43QT_BEGIN_NAMESPACE
44
45#ifndef QFONTCACHE_DECREASE_TRIGGER_LIMIT
46# define QFONTCACHE_DECREASE_TRIGGER_LIMIT 256
47#endif
48
49bool QFontDef::exactMatch(const QFontDef &other) const
50{
51 /*
52 QFontDef comparison is more complicated than just simple
53 per-member comparisons.
54
55 When comparing point/pixel sizes, either point or pixelsize
56 could be -1. in This case we have to compare the non negative
57 size value.
58
59 This test will fail if the point-sizes differ by 1/2 point or
60 more or they do not round to the same value. We have to do this
61 since our API still uses 'int' point-sizes in the API, but store
62 deci-point-sizes internally.
63
64 To compare the family members, we need to parse the font names
65 and compare the family/foundry strings separately. This allows
66 us to compare e.g. "Helvetica" and "Helvetica [Adobe]" with
67 positive results.
68 */
69 if (pixelSize != -1 && other.pixelSize != -1) {
70 if (pixelSize != other.pixelSize)
71 return false;
72 } else if (pointSize != -1 && other.pointSize != -1) {
73 if (pointSize != other.pointSize)
74 return false;
75 } else {
76 return false;
77 }
78
79 if (!ignorePitch && !other.ignorePitch && fixedPitch != other.fixedPitch)
80 return false;
81
82 if (stretch != 0 && other.stretch != 0 && stretch != other.stretch)
83 return false;
84
85 QString this_family, this_foundry, other_family, other_foundry;
86 for (int i = 0; i < families.size(); ++i) {
87 QFontDatabasePrivate::parseFontName(name: families.at(i), foundry&: this_foundry, family&: this_family);
88 QFontDatabasePrivate::parseFontName(name: other.families.at(i), foundry&: other_foundry, family&: other_family);
89 if (this_family != other_family || this_foundry != other_foundry)
90 return false;
91 }
92
93 if (variableAxisValues != other.variableAxisValues)
94 return false;
95
96 return (styleHint == other.styleHint
97 && styleStrategy == other.styleStrategy
98 && weight == other.weight
99 && style == other.style
100 && this_family == other_family
101 && (styleName.isEmpty() || other.styleName.isEmpty() || styleName == other.styleName)
102 && (this_foundry.isEmpty()
103 || other_foundry.isEmpty()
104 || this_foundry == other_foundry)
105 );
106}
107
108extern bool qt_is_tty_app;
109
110Q_GUI_EXPORT int qt_defaultDpiX()
111{
112 if (QCoreApplication::instance()->testAttribute(attribute: Qt::AA_Use96Dpi))
113 return 96;
114
115 if (qt_is_tty_app)
116 return 75;
117
118 if (const QScreen *screen = QGuiApplication::primaryScreen())
119 return qRound(d: screen->logicalDotsPerInchX());
120
121 //PI has not been initialised, or it is being initialised. Give a default dpi
122 return 100;
123}
124
125Q_GUI_EXPORT int qt_defaultDpiY()
126{
127 if (QCoreApplication::instance()->testAttribute(attribute: Qt::AA_Use96Dpi))
128 return 96;
129
130 if (qt_is_tty_app)
131 return 75;
132
133 if (const QScreen *screen = QGuiApplication::primaryScreen())
134 return qRound(d: screen->logicalDotsPerInchY());
135
136 //PI has not been initialised, or it is being initialised. Give a default dpi
137 return 100;
138}
139
140Q_GUI_EXPORT int qt_defaultDpi()
141{
142 return qt_defaultDpiY();
143}
144
145/* Helper function to convert between legacy Qt and OpenType font weights. */
146static int convertWeights(int weight, bool inverted)
147{
148 static constexpr std::array<int, 2> legacyToOpenTypeMap[] = {
149 { 0, QFont::Thin }, { 12, QFont::ExtraLight }, { 25, QFont::Light },
150 { 50, QFont::Normal }, { 57, QFont::Medium }, { 63, QFont::DemiBold },
151 { 75, QFont::Bold }, { 81, QFont::ExtraBold }, { 87, QFont::Black },
152 };
153
154 int closestDist = INT_MAX;
155 int result = -1;
156
157 // Go through and find the closest mapped value
158 for (auto mapping : legacyToOpenTypeMap) {
159 const int weightOld = mapping[ inverted];
160 const int weightNew = mapping[!inverted];
161 const int dist = qAbs(t: weightOld - weight);
162 if (dist < closestDist) {
163 result = weightNew;
164 closestDist = dist;
165 } else {
166 // Break early since following values will be further away
167 break;
168 }
169 }
170
171 return result;
172}
173
174// Splits the family string on a comma and returns the list based on that
175static QStringList splitIntoFamilies(const QString &family)
176{
177 QStringList familyList;
178 if (family.isEmpty())
179 return familyList;
180 const auto list = QStringView{family}.split(sep: u',');
181 const int numFamilies = list.size();
182 familyList.reserve(asize: numFamilies);
183 for (int i = 0; i < numFamilies; ++i) {
184 auto str = list.at(i).trimmed();
185 if ((str.startsWith(c: u'"') && str.endsWith(c: u'"'))
186 || (str.startsWith(c: u'\'') && str.endsWith(c: u'\''))) {
187 str = str.mid(pos: 1, n: str.size() - 2);
188 }
189 familyList << str.toString();
190 }
191 return familyList;
192}
193
194/* Converts from legacy Qt font weight (Qt < 6.0) to OpenType font weight (Qt >= 6.0) */
195Q_GUI_EXPORT int qt_legacyToOpenTypeWeight(int weight)
196{
197 return convertWeights(weight, inverted: false);
198}
199
200/* Converts from OpenType font weight (Qt >= 6.0) to legacy Qt font weight (Qt < 6.0) */
201Q_GUI_EXPORT int qt_openTypeToLegacyWeight(int weight)
202{
203 return convertWeights(weight, inverted: true);
204}
205
206QFontPrivate::QFontPrivate()
207 : engineData(nullptr), dpi(qt_defaultDpi()),
208 underline(false), overline(false), strikeOut(false), kerning(true),
209 capital(0), letterSpacingIsAbsolute(false), scFont(nullptr)
210{
211}
212
213QFontPrivate::QFontPrivate(const QFontPrivate &other)
214 : request(other.request), engineData(nullptr), dpi(other.dpi),
215 underline(other.underline), overline(other.overline),
216 strikeOut(other.strikeOut), kerning(other.kerning),
217 capital(other.capital), letterSpacingIsAbsolute(other.letterSpacingIsAbsolute),
218 letterSpacing(other.letterSpacing), wordSpacing(other.wordSpacing),
219 features(other.features), scFont(other.scFont)
220{
221 if (scFont && scFont != this)
222 scFont->ref.ref();
223}
224
225QFontPrivate::~QFontPrivate()
226{
227 if (engineData && !engineData->ref.deref())
228 delete engineData;
229 engineData = nullptr;
230 if (scFont && scFont != this) {
231 if (!scFont->ref.deref())
232 delete scFont;
233 }
234 scFont = nullptr;
235}
236
237extern QRecursiveMutex *qt_fontdatabase_mutex();
238
239#define QT_FONT_ENGINE_FROM_DATA(data, script) data->engines[script]
240
241QFontEngine *QFontPrivate::engineForScript(int script) const
242{
243 QMutexLocker locker(qt_fontdatabase_mutex());
244 if (script <= QChar::Script_Latin)
245 script = QChar::Script_Common;
246 if (engineData && engineData->fontCacheId != QFontCache::instance()->id()) {
247 // throw out engineData that came from a different thread
248 if (!engineData->ref.deref())
249 delete engineData;
250 engineData = nullptr;
251 }
252 if (!engineData || !QT_FONT_ENGINE_FROM_DATA(engineData, script))
253 QFontDatabasePrivate::load(d: this, script);
254 return QT_FONT_ENGINE_FROM_DATA(engineData, script);
255}
256
257void QFontPrivate::alterCharForCapitalization(QChar &c) const {
258 switch (capital) {
259 case QFont::AllUppercase:
260 case QFont::SmallCaps:
261 c = c.toUpper();
262 break;
263 case QFont::AllLowercase:
264 c = c.toLower();
265 break;
266 case QFont::MixedCase:
267 break;
268 }
269}
270
271QFontPrivate *QFontPrivate::smallCapsFontPrivate() const
272{
273 if (scFont)
274 return scFont;
275 QFont font(const_cast<QFontPrivate *>(this));
276 qreal pointSize = font.pointSizeF();
277 if (pointSize > 0)
278 font.setPointSizeF(pointSize * .7);
279 else
280 font.setPixelSize((font.pixelSize() * 7 + 5) / 10);
281 scFont = font.d.data();
282 if (scFont != this)
283 scFont->ref.ref();
284 return scFont;
285}
286
287
288void QFontPrivate::resolve(uint mask, const QFontPrivate *other)
289{
290 Q_ASSERT(other != nullptr);
291
292 dpi = other->dpi;
293
294 if ((mask & QFont::AllPropertiesResolved) == QFont::AllPropertiesResolved) return;
295
296 // assign the unset-bits with the set-bits of the other font def
297 if (!(mask & QFont::FamiliesResolved))
298 request.families = other->request.families;
299
300 if (! (mask & QFont::StyleNameResolved))
301 request.styleName = other->request.styleName;
302
303 if (! (mask & QFont::SizeResolved)) {
304 request.pointSize = other->request.pointSize;
305 request.pixelSize = other->request.pixelSize;
306 }
307
308 if (! (mask & QFont::StyleHintResolved))
309 request.styleHint = other->request.styleHint;
310
311 if (! (mask & QFont::StyleStrategyResolved))
312 request.styleStrategy = other->request.styleStrategy;
313
314 if (! (mask & QFont::WeightResolved))
315 request.weight = other->request.weight;
316
317 if (! (mask & QFont::StyleResolved))
318 request.style = other->request.style;
319
320 if (! (mask & QFont::FixedPitchResolved))
321 request.fixedPitch = other->request.fixedPitch;
322
323 if (! (mask & QFont::StretchResolved))
324 request.stretch = other->request.stretch;
325
326 if (! (mask & QFont::HintingPreferenceResolved))
327 request.hintingPreference = other->request.hintingPreference;
328
329 if (! (mask & QFont::UnderlineResolved))
330 underline = other->underline;
331
332 if (! (mask & QFont::OverlineResolved))
333 overline = other->overline;
334
335 if (! (mask & QFont::StrikeOutResolved))
336 strikeOut = other->strikeOut;
337
338 if (! (mask & QFont::KerningResolved))
339 kerning = other->kerning;
340
341 if (! (mask & QFont::LetterSpacingResolved)) {
342 letterSpacing = other->letterSpacing;
343 letterSpacingIsAbsolute = other->letterSpacingIsAbsolute;
344 }
345 if (! (mask & QFont::WordSpacingResolved))
346 wordSpacing = other->wordSpacing;
347 if (! (mask & QFont::CapitalizationResolved))
348 capital = other->capital;
349
350 if (!(mask & QFont::FeaturesResolved))
351 features = other->features;
352
353 if (!(mask & QFont::VariableAxesResolved))
354 request.variableAxisValues = other->request.variableAxisValues;
355}
356
357bool QFontPrivate::hasVariableAxis(QFont::Tag tag, float value) const
358{
359 return request.variableAxisValues.contains(key: tag) && request.variableAxisValues.value(key: tag) == value;
360}
361
362void QFontPrivate::setVariableAxis(QFont::Tag tag, float value)
363{
364 request.variableAxisValues.insert(key: tag, value);
365}
366
367void QFontPrivate::unsetVariableAxis(QFont::Tag tag)
368{
369 request.variableAxisValues.remove(key: tag);
370}
371
372void QFontPrivate::setFeature(QFont::Tag tag, quint32 value)
373{
374 features.insert(key: tag, value);
375}
376
377void QFontPrivate::unsetFeature(QFont::Tag tag)
378{
379 features.remove(key: tag);
380}
381
382
383QFontEngineData::QFontEngineData()
384 : ref(0), fontCacheId(QFontCache::instance()->id())
385{
386 memset(s: engines, c: 0, n: QChar::ScriptCount * sizeof(QFontEngine *));
387}
388
389QFontEngineData::~QFontEngineData()
390{
391 Q_ASSERT(ref.loadRelaxed() == 0);
392 for (int i = 0; i < QChar::ScriptCount; ++i) {
393 if (engines[i]) {
394 if (!engines[i]->ref.deref())
395 delete engines[i];
396 engines[i] = nullptr;
397 }
398 }
399}
400
401
402
403
404/*!
405 \class QFont
406 \reentrant
407
408 \brief The QFont class specifies a query for a font used for drawing text.
409
410 \ingroup painting
411 \ingroup appearance
412 \ingroup shared
413 \ingroup richtext-processing
414 \inmodule QtGui
415
416 QFont can be regarded as a query for one or more fonts on the system.
417
418 When you create a QFont object you specify various attributes that
419 you want the font to have. Qt will use the font with the specified
420 attributes, or if no matching font exists, Qt will use the closest
421 matching installed font. The attributes of the font that is
422 actually used are retrievable from a QFontInfo object. If the
423 window system provides an exact match exactMatch() returns \c true.
424 Use QFontMetricsF to get measurements, e.g. the pixel length of a
425 string using QFontMetrics::width().
426
427 Attributes which are not specifically set will not affect the font
428 selection algorithm, and default values will be preferred instead.
429
430 To load a specific physical font, typically represented by a single file,
431 use QRawFont instead.
432
433 Note that a QGuiApplication instance must exist before a QFont can be
434 used. You can set the application's default font with
435 QGuiApplication::setFont().
436
437 If a chosen font does not include all the characters that
438 need to be displayed, QFont will try to find the characters in the
439 nearest equivalent fonts. When a QPainter draws a character from a
440 font the QFont will report whether or not it has the character; if
441 it does not, QPainter will draw an unfilled square.
442
443 Create QFonts like this:
444
445 \snippet code/src_gui_text_qfont.cpp 0
446
447 The attributes set in the constructor can also be set later, e.g.
448 setFamily(), setPointSize(), setPointSizeF(), setWeight() and
449 setItalic(). The remaining attributes must be set after
450 construction, e.g. setBold(), setUnderline(), setOverline(),
451 setStrikeOut() and setFixedPitch(). QFontInfo objects should be
452 created \e after the font's attributes have been set. A QFontInfo
453 object will not change, even if you change the font's
454 attributes. The corresponding "get" functions, e.g. family(),
455 pointSize(), etc., return the values that were set, even though
456 the values used may differ. The actual values are available from a
457 QFontInfo object.
458
459 If the requested font family is unavailable you can influence the
460 \l{#fontmatching}{font matching algorithm} by choosing a
461 particular \l{QFont::StyleHint} and \l{QFont::StyleStrategy} with
462 setStyleHint(). The default family (corresponding to the current
463 style hint) is returned by defaultFamily().
464
465 You can provide substitutions for font family names using
466 insertSubstitution() and insertSubstitutions(). Substitutions can
467 be removed with removeSubstitutions(). Use substitute() to retrieve
468 a family's first substitute, or the family name itself if it has
469 no substitutes. Use substitutes() to retrieve a list of a family's
470 substitutes (which may be empty). After substituting a font, you must
471 trigger the updating of the font by destroying and re-creating all
472 QFont objects.
473
474 Every QFont has a key() which you can use, for example, as the key
475 in a cache or dictionary. If you want to store a user's font
476 preferences you could use QSettings, writing the font information
477 with toString() and reading it back with fromString(). The
478 operator<<() and operator>>() functions are also available, but
479 they work on a data stream.
480
481 It is possible to set the height of characters shown on the screen
482 to a specified number of pixels with setPixelSize(); however using
483 setPointSize() has a similar effect and provides device
484 independence.
485
486 Loading fonts can be expensive, especially on X11. QFont contains
487 extensive optimizations to make the copying of QFont objects fast,
488 and to cache the results of the slow window system functions it
489 depends upon.
490
491 \target fontmatching
492 The font matching algorithm works as follows:
493 \list 1
494 \li The specified font families (set by setFamilies()) are searched for.
495 \li If not, a replacement font that supports the writing system is
496 selected. The font matching algorithm will try to find the
497 best match for all the properties set in the QFont. How this is
498 done varies from platform to platform.
499 \li If no font exists on the system that can support the text,
500 then special "missing character" boxes will be shown in its place.
501 \endlist
502
503 \note If the selected font, though supporting the writing system in general,
504 is missing glyphs for one or more specific characters, then Qt will try to
505 find a fallback font for this or these particular characters. This feature
506 can be disabled using QFont::NoFontMerging style strategy.
507
508 In Windows a request for the "Courier" font is automatically changed to
509 "Courier New", an improved version of Courier that allows for smooth scaling.
510 The older "Courier" bitmap font can be selected by setting the PreferBitmap
511 style strategy (see setStyleStrategy()).
512
513 Once a font is found, the remaining attributes are matched in order of
514 priority:
515 \list 1
516 \li fixedPitch()
517 \li pointSize() (see below)
518 \li weight()
519 \li style()
520 \endlist
521
522 If you have a font which matches on family, even if none of the
523 other attributes match, this font will be chosen in preference to
524 a font which doesn't match on family but which does match on the
525 other attributes. This is because font family is the dominant
526 search criteria.
527
528 The point size is defined to match if it is within 20% of the
529 requested point size. When several fonts match and are only
530 distinguished by point size, the font with the closest point size
531 to the one requested will be chosen.
532
533 The actual family, font size, weight and other font attributes
534 used for drawing text will depend on what's available for the
535 chosen family under the window system. A QFontInfo object can be
536 used to determine the actual values used for drawing the text.
537
538 Examples:
539
540 \snippet code/src_gui_text_qfont.cpp 1
541 If you had both an Adobe and a Cronyx Helvetica, you might get
542 either.
543
544 \snippet code/src_gui_text_qfont.cpp 2
545
546 You can specify the foundry you want in the family name. The font f
547 in the above example will be set to "Helvetica
548 [Cronyx]".
549
550 To determine the attributes of the font actually used in the window
551 system, use a QFontInfo object, e.g.
552
553 \snippet code/src_gui_text_qfont.cpp 3
554
555 To find out font metrics use a QFontMetrics object, e.g.
556
557 \snippet code/src_gui_text_qfont.cpp 4
558
559 For more general information on fonts, see the
560 \l{comp.fonts FAQ}{comp.fonts FAQ}.
561 Information on encodings can be found from the
562 \l{UTR17} page.
563
564 \sa QFontMetrics, QFontInfo, QFontDatabase
565*/
566
567/*!
568 \internal
569 \enum QFont::ResolveProperties
570
571 This enum describes the properties of a QFont that can be set on a font
572 individually and then considered resolved.
573
574 \value FamilyResolved
575 \value FamiliesResolved
576 \value SizeResolved
577 \value StyleHintResolved
578 \value StyleStrategyResolved
579 \value WeightResolved
580 \value StyleResolved
581 \value UnderlineResolved
582 \value OverlineResolved
583 \value StrikeOutResolved
584 \value FixedPitchResolved
585 \value StretchResolved
586 \value KerningResolved
587 \value CapitalizationResolved
588 \value LetterSpacingResolved
589 \value WordSpacingResolved
590 \value CompletelyResolved
591*/
592
593/*!
594 \enum QFont::Style
595
596 This enum describes the different styles of glyphs that are used to
597 display text.
598
599 \value StyleNormal Normal glyphs used in unstyled text.
600 \value StyleItalic Italic glyphs that are specifically designed for
601 the purpose of representing italicized text.
602 \value StyleOblique Glyphs with an italic appearance that are typically
603 based on the unstyled glyphs, but are not fine-tuned
604 for the purpose of representing italicized text.
605
606 \sa Weight
607*/
608
609/*!
610 \fn QFont &QFont::operator=(QFont &&other)
611
612 Move-assigns \a other to this QFont instance.
613
614 \since 5.2
615*/
616
617/*!
618 \since 5.13
619 Constructs a font from \a font for use on the paint device \a pd.
620*/
621QFont::QFont(const QFont &font, const QPaintDevice *pd)
622 : resolve_mask(font.resolve_mask)
623{
624 Q_ASSERT(pd);
625 const int dpi = pd->logicalDpiY();
626 if (font.d->dpi != dpi) {
627 d = new QFontPrivate(*font.d);
628 d->dpi = dpi;
629 } else {
630 d = font.d;
631 }
632}
633
634/*!
635 \internal
636*/
637QFont::QFont(QFontPrivate *data)
638 : d(data), resolve_mask(QFont::AllPropertiesResolved)
639{
640}
641
642/*! \internal
643 Detaches the font object from common font data.
644*/
645void QFont::detach()
646{
647 if (d->ref.loadRelaxed() == 1) {
648 if (d->engineData && !d->engineData->ref.deref())
649 delete d->engineData;
650 d->engineData = nullptr;
651 if (d->scFont && d->scFont != d.data()) {
652 if (!d->scFont->ref.deref())
653 delete d->scFont;
654 }
655 d->scFont = nullptr;
656 return;
657 }
658
659 d.detach();
660}
661
662/*!
663 \internal
664 Detaches the font object from common font attributes data.
665 Call this instead of QFont::detach() if the only font attributes data
666 has been changed (underline, letterSpacing, kerning, etc.).
667*/
668void QFontPrivate::detachButKeepEngineData(QFont *font)
669{
670 if (font->d->ref.loadRelaxed() == 1)
671 return;
672
673 QFontEngineData *engineData = font->d->engineData;
674 if (engineData)
675 engineData->ref.ref();
676 font->d.detach();
677 font->d->engineData = engineData;
678}
679
680/*!
681 Constructs a font object that uses the application's default font.
682
683 \sa QGuiApplication::setFont(), QGuiApplication::font()
684*/
685QFont::QFont()
686 : d(QGuiApplicationPrivate::instance() ? QGuiApplication::font().d.data() : new QFontPrivate()), resolve_mask(0)
687{
688}
689
690/*!
691 Constructs a font object with the specified \a family, \a
692 pointSize, \a weight and \a italic settings.
693
694 If \a pointSize is zero or negative, the point size of the font
695 is set to a system-dependent default value. Generally, this is
696 12 points.
697
698 The \a family name may optionally also include a foundry name,
699 e.g. "Helvetica [Cronyx]". If the \a family is
700 available from more than one foundry and the foundry isn't
701 specified, an arbitrary foundry is chosen. If the family isn't
702 available a family will be set using the \l{QFont}{font matching}
703 algorithm.
704
705 This will split the family string on a comma and call setFamilies() with the
706 resulting list. To preserve a font that uses a comma in its name, use
707 the constructor that takes a QStringList.
708
709 \sa Weight, setFamily(), setPointSize(), setWeight(), setItalic(),
710 setStyleHint(), setFamilies(), QGuiApplication::font()
711*/
712QFont::QFont(const QString &family, int pointSize, int weight, bool italic)
713 : d(new QFontPrivate()), resolve_mask(QFont::FamiliesResolved)
714{
715 if (pointSize <= 0) {
716 pointSize = 12;
717 } else {
718 resolve_mask |= QFont::SizeResolved;
719 }
720
721 if (weight < 0) {
722 weight = Normal;
723 } else {
724 resolve_mask |= QFont::WeightResolved | QFont::StyleResolved;
725 }
726
727 if (italic)
728 resolve_mask |= QFont::StyleResolved;
729
730 d->request.families = splitIntoFamilies(family);
731 d->request.pointSize = qreal(pointSize);
732 d->request.pixelSize = -1;
733 d->request.weight = weight;
734 d->request.style = italic ? QFont::StyleItalic : QFont::StyleNormal;
735}
736
737/*!
738 Constructs a font object with the specified \a families, \a
739 pointSize, \a weight and \a italic settings.
740
741 If \a pointSize is zero or negative, the point size of the font
742 is set to a system-dependent default value. Generally, this is
743 12 points.
744
745 Each family name entry in \a families may optionally also include
746 a foundry name, e.g. "Helvetica [Cronyx]". If the family is
747 available from more than one foundry and the foundry isn't
748 specified, an arbitrary foundry is chosen. If the family isn't
749 available a family will be set using the \l{QFont}{font matching}
750 algorithm.
751
752 \sa Weight, setPointSize(), setWeight(), setItalic(),
753 setStyleHint(), setFamilies(), QGuiApplication::font()
754 */
755QFont::QFont(const QStringList &families, int pointSize, int weight, bool italic)
756 : d(new QFontPrivate()), resolve_mask(QFont::FamiliesResolved)
757{
758 if (pointSize <= 0)
759 pointSize = 12;
760 else
761 resolve_mask |= QFont::SizeResolved;
762
763 if (weight < 0)
764 weight = Normal;
765 else
766 resolve_mask |= QFont::WeightResolved | QFont::StyleResolved;
767
768 if (italic)
769 resolve_mask |= QFont::StyleResolved;
770
771 d->request.families = families;
772 d->request.pointSize = qreal(pointSize);
773 d->request.pixelSize = -1;
774 d->request.weight = weight;
775 d->request.style = italic ? QFont::StyleItalic : QFont::StyleNormal;
776}
777
778/*!
779 Constructs a font that is a copy of \a font.
780*/
781QFont::QFont(const QFont &font)
782 : d(font.d), resolve_mask(font.resolve_mask)
783{
784}
785
786/*!
787 Destroys the font object and frees all allocated resources.
788*/
789QFont::~QFont()
790{
791}
792
793/*!
794 Assigns \a font to this font and returns a reference to it.
795*/
796QFont &QFont::operator=(const QFont &font)
797{
798 d = font.d;
799 resolve_mask = font.resolve_mask;
800 return *this;
801}
802
803/*!
804 \fn void QFont::swap(QFont &other)
805 \since 5.0
806
807 Swaps this font instance with \a other. This function is very fast
808 and never fails.
809*/
810
811/*!
812 Returns the requested font family name. This will always be the same
813 as the first entry in the families() call.
814
815 \sa setFamily(), substitutes(), substitute(), setFamilies(), families()
816*/
817QString QFont::family() const
818{
819 return d->request.families.isEmpty() ? QString() : d->request.families.constFirst();
820}
821
822/*!
823 Sets the family name of the font. The name is case insensitive and
824 may include a foundry name.
825
826 The \a family name may optionally also include a foundry name,
827 e.g. "Helvetica [Cronyx]". If the \a family is
828 available from more than one foundry and the foundry isn't
829 specified, an arbitrary foundry is chosen. If the family isn't
830 available a family will be set using the \l{QFont}{font matching}
831 algorithm.
832
833 \sa family(), setStyleHint(), setFamilies(), families(), QFontInfo
834*/
835void QFont::setFamily(const QString &family)
836{
837 setFamilies(QStringList(family));
838}
839
840/*!
841 \since 4.8
842
843 Returns the requested font style name. This can be used to match the
844 font with irregular styles (that can't be normalized in other style
845 properties).
846
847 \sa setFamily(), setStyle()
848*/
849QString QFont::styleName() const
850{
851 return d->request.styleName;
852}
853
854/*!
855 \since 4.8
856
857 Sets the style name of the font to \a styleName. When set, other style properties
858 like \l style() and \l weight() will be ignored for font matching, though they may be
859 simulated afterwards if supported by the platform's font engine.
860
861 Due to the lower quality of artificially simulated styles, and the lack of full cross
862 platform support, it is not recommended to use matching by style name together with
863 matching by style properties
864
865 \sa styleName()
866*/
867void QFont::setStyleName(const QString &styleName)
868{
869 if ((resolve_mask & QFont::StyleNameResolved) && d->request.styleName == styleName)
870 return;
871
872 detach();
873
874 d->request.styleName = styleName;
875 resolve_mask |= QFont::StyleNameResolved;
876}
877
878/*!
879 Returns the point size of the font. Returns -1 if the font size
880 was specified in pixels.
881
882 \sa setPointSize(), pointSizeF()
883*/
884int QFont::pointSize() const
885{
886 return qRound(d: d->request.pointSize);
887}
888
889/*!
890 \since 4.8
891
892 \enum QFont::HintingPreference
893
894 This enum describes the different levels of hinting that can be applied
895 to glyphs to improve legibility on displays where it might be warranted
896 by the density of pixels.
897
898 \value PreferDefaultHinting Use the default hinting level for the target platform.
899 \value PreferNoHinting If possible, render text without hinting the outlines
900 of the glyphs. The text layout will be typographically accurate and
901 scalable, using the same metrics as are used e.g. when printing.
902 \value PreferVerticalHinting If possible, render text with no horizontal hinting,
903 but align glyphs to the pixel grid in the vertical direction. The text will appear
904 crisper on displays where the density is too low to give an accurate rendering
905 of the glyphs. But since the horizontal metrics of the glyphs are unhinted, the text's
906 layout will be scalable to higher density devices (such as printers) without impacting
907 details such as line breaks.
908 \value PreferFullHinting If possible, render text with hinting in both horizontal and
909 vertical directions. The text will be altered to optimize legibility on the target
910 device, but since the metrics will depend on the target size of the text, the positions
911 of glyphs, line breaks, and other typographical detail will not scale, meaning that a
912 text layout may look different on devices with different pixel densities.
913
914 Please note that this enum only describes a preference, as the full range of hinting levels
915 are not supported on all of Qt's supported platforms. The following table details the effect
916 of a given hinting preference on a selected set of target platforms.
917
918 \table
919 \header
920 \li
921 \li PreferDefaultHinting
922 \li PreferNoHinting
923 \li PreferVerticalHinting
924 \li PreferFullHinting
925 \row
926 \li Windows and DirectWrite enabled in Qt
927 \li Full hinting
928 \li Vertical hinting
929 \li Vertical hinting
930 \li Full hinting
931 \row
932 \li FreeType
933 \li Operating System setting
934 \li No hinting
935 \li Vertical hinting (light)
936 \li Full hinting
937 \row
938 \li Cocoa on \macos
939 \li No hinting
940 \li No hinting
941 \li No hinting
942 \li No hinting
943 \endtable
944
945*/
946
947/*!
948 \since 4.8
949
950 Set the preference for the hinting level of the glyphs to \a hintingPreference. This is a hint
951 to the underlying font rendering system to use a certain level of hinting, and has varying
952 support across platforms. See the table in the documentation for QFont::HintingPreference for
953 more details.
954
955 The default hinting preference is QFont::PreferDefaultHinting.
956*/
957void QFont::setHintingPreference(HintingPreference hintingPreference)
958{
959 if ((resolve_mask & QFont::HintingPreferenceResolved) && d->request.hintingPreference == hintingPreference)
960 return;
961
962 detach();
963
964 d->request.hintingPreference = hintingPreference;
965
966 resolve_mask |= QFont::HintingPreferenceResolved;
967}
968
969/*!
970 \since 4.8
971
972 Returns the currently preferred hinting level for glyphs rendered with this font.
973*/
974QFont::HintingPreference QFont::hintingPreference() const
975{
976 return QFont::HintingPreference(d->request.hintingPreference);
977}
978
979/*!
980 Sets the point size to \a pointSize. The point size must be
981 greater than zero.
982
983 \sa pointSize(), setPointSizeF()
984*/
985void QFont::setPointSize(int pointSize)
986{
987 if (pointSize <= 0) {
988 qWarning(msg: "QFont::setPointSize: Point size <= 0 (%d), must be greater than 0", pointSize);
989 return;
990 }
991
992 if ((resolve_mask & QFont::SizeResolved) && d->request.pointSize == qreal(pointSize))
993 return;
994
995 detach();
996
997 d->request.pointSize = qreal(pointSize);
998 d->request.pixelSize = -1;
999
1000 resolve_mask |= QFont::SizeResolved;
1001}
1002
1003/*!
1004 Sets the point size to \a pointSize. The point size must be
1005 greater than zero. The requested precision may not be achieved on
1006 all platforms.
1007
1008 \sa pointSizeF(), setPointSize(), setPixelSize()
1009*/
1010void QFont::setPointSizeF(qreal pointSize)
1011{
1012 if (pointSize <= 0) {
1013 qWarning(msg: "QFont::setPointSizeF: Point size <= 0 (%f), must be greater than 0", pointSize);
1014 return;
1015 }
1016
1017 if ((resolve_mask & QFont::SizeResolved) && d->request.pointSize == pointSize)
1018 return;
1019
1020 detach();
1021
1022 d->request.pointSize = pointSize;
1023 d->request.pixelSize = -1;
1024
1025 resolve_mask |= QFont::SizeResolved;
1026}
1027
1028/*!
1029 Returns the point size of the font. Returns -1 if the font size was
1030 specified in pixels.
1031
1032 \sa pointSize(), setPointSizeF(), pixelSize(), QFontInfo::pointSize(), QFontInfo::pixelSize()
1033*/
1034qreal QFont::pointSizeF() const
1035{
1036 return d->request.pointSize;
1037}
1038
1039/*!
1040 Sets the font size to \a pixelSize pixels, with a maxiumum size
1041 of an unsigned 16-bit integer.
1042
1043 Using this function makes the font device dependent. Use
1044 setPointSize() or setPointSizeF() to set the size of the font
1045 in a device independent manner.
1046
1047 \sa pixelSize()
1048*/
1049void QFont::setPixelSize(int pixelSize)
1050{
1051 if (pixelSize <= 0) {
1052 qWarning(msg: "QFont::setPixelSize: Pixel size <= 0 (%d)", pixelSize);
1053 return;
1054 }
1055
1056 if ((resolve_mask & QFont::SizeResolved) && d->request.pixelSize == qreal(pixelSize))
1057 return;
1058
1059 detach();
1060
1061 d->request.pixelSize = pixelSize;
1062 d->request.pointSize = -1;
1063
1064 resolve_mask |= QFont::SizeResolved;
1065}
1066
1067/*!
1068 Returns the pixel size of the font if it was set with
1069 setPixelSize(). Returns -1 if the size was set with setPointSize()
1070 or setPointSizeF().
1071
1072 \sa setPixelSize(), pointSize(), QFontInfo::pointSize(), QFontInfo::pixelSize()
1073*/
1074int QFont::pixelSize() const
1075{
1076 return d->request.pixelSize;
1077}
1078
1079/*!
1080 \fn bool QFont::italic() const
1081
1082 Returns \c true if the style() of the font is not QFont::StyleNormal
1083
1084 \sa setItalic(), style()
1085*/
1086
1087/*!
1088 \fn void QFont::setItalic(bool enable)
1089
1090 Sets the style() of the font to QFont::StyleItalic if \a enable is true;
1091 otherwise the style is set to QFont::StyleNormal.
1092
1093 \note If styleName() is set, this value may be ignored, or if supported
1094 on the platform, the font may be rendered tilted instead of picking a
1095 designed italic font-variant.
1096
1097 \sa italic(), QFontInfo
1098*/
1099
1100/*!
1101 Returns the style of the font.
1102
1103 \sa setStyle()
1104*/
1105QFont::Style QFont::style() const
1106{
1107 return (QFont::Style)d->request.style;
1108}
1109
1110
1111/*!
1112 Sets the style of the font to \a style.
1113
1114 \sa italic(), QFontInfo
1115*/
1116void QFont::setStyle(Style style)
1117{
1118 if ((resolve_mask & QFont::StyleResolved) && d->request.style == style)
1119 return;
1120
1121 detach();
1122
1123 d->request.style = style;
1124 resolve_mask |= QFont::StyleResolved;
1125}
1126
1127/*!
1128 Returns the weight of the font, using the same scale as the
1129 \l{QFont::Weight} enumeration.
1130
1131 \sa setWeight(), Weight, QFontInfo
1132*/
1133QFont::Weight QFont::weight() const
1134{
1135 return static_cast<Weight>(d->request.weight);
1136}
1137
1138/*!
1139 \enum QFont::Weight
1140
1141 Qt uses a weighting scale from 1 to 1000 compatible with OpenType. A weight of 1 will be
1142 thin, whilst 1000 will be extremely black.
1143
1144 This enum contains the predefined font weights:
1145
1146 \value Thin 100
1147 \value ExtraLight 200
1148 \value Light 300
1149 \value Normal 400
1150 \value Medium 500
1151 \value DemiBold 600
1152 \value Bold 700
1153 \value ExtraBold 800
1154 \value Black 900
1155*/
1156
1157#if QT_DEPRECATED_SINCE(6, 0)
1158/*!
1159 \deprecated [6.0] Use setWeight() instead.
1160
1161 Sets the weight of the font to \a legacyWeight using the legacy font
1162 weight scale of Qt 5 and previous versions.
1163
1164 Since Qt 6, the OpenType standard's font weight scale is used instead
1165 of a non-standard scale. This requires conversion from values that
1166 use the old scale. For convenience, this function may be used when
1167 porting from code which uses the old weight scale.
1168
1169 \note If styleName() is set, this value may be ignored for font selection.
1170
1171 \sa setWeight(), weight(), QFontInfo
1172*/
1173void QFont::setLegacyWeight(int legacyWeight)
1174{
1175 setWeight(QFont::Weight(qt_legacyToOpenTypeWeight(weight: legacyWeight)));
1176}
1177
1178/*!
1179 \deprecated [6.0] Use weight() instead.
1180
1181 Returns the weight of the font converted to the non-standard font
1182 weight scale used in Qt 5 and earlier versions.
1183
1184 Since Qt 6, the OpenType standard's font weight scale is used instead
1185 of a non-standard scale. This requires conversion from values that
1186 use the old scale. For convenience, this function may be used when
1187 porting from code which uses the old weight scale.
1188
1189 \sa setWeight(), weight(), QFontInfo
1190*/
1191int QFont::legacyWeight() const
1192{
1193 return qt_openTypeToLegacyWeight(weight: weight());
1194}
1195#endif // QT_DEPRECATED_SINCE(6, 0)
1196
1197/*!
1198 Sets the weight of the font to \a weight, using the scale defined by
1199 \l QFont::Weight enumeration.
1200
1201 \note If styleName() is set, this value may be ignored for font selection.
1202
1203 \sa weight(), QFontInfo
1204*/
1205void QFont::setWeight(QFont::Weight weight)
1206{
1207 const int weightValue = qBound(QFONT_WEIGHT_MIN, val: static_cast<int>(weight), QFONT_WEIGHT_MAX);
1208 if (weightValue != static_cast<int>(weight)) {
1209 qWarning() << "QFont::setWeight: Weight must be between 1 and 1000, attempted to set "
1210 << static_cast<int>(weight);
1211 }
1212
1213 if ((resolve_mask & QFont::WeightResolved) && d->request.weight == weightValue)
1214 return;
1215
1216 detach();
1217
1218 d->request.weight = weightValue;
1219 resolve_mask |= QFont::WeightResolved;
1220}
1221
1222/*!
1223 \fn bool QFont::bold() const
1224
1225 Returns \c true if weight() is a value greater than
1226 \l{Weight}{QFont::Medium}; otherwise returns \c false.
1227
1228 \sa weight(), setBold(), QFontInfo::bold()
1229*/
1230
1231/*!
1232 \fn void QFont::setBold(bool enable)
1233
1234 If \a enable is true sets the font's weight to
1235 \l{Weight}{QFont::Bold};
1236 otherwise sets the weight to \l{Weight}{QFont::Normal}.
1237
1238 For finer boldness control use setWeight().
1239
1240 \note If styleName() is set, this value may be ignored, or if supported
1241 on the platform, the font artificially embolded.
1242
1243 \sa bold(), setWeight()
1244*/
1245
1246/*!
1247 Returns \c true if underline has been set; otherwise returns \c false.
1248
1249 \sa setUnderline()
1250*/
1251bool QFont::underline() const
1252{
1253 return d->underline;
1254}
1255
1256/*!
1257 If \a enable is true, sets underline on; otherwise sets underline
1258 off.
1259
1260 \sa underline(), QFontInfo
1261*/
1262void QFont::setUnderline(bool enable)
1263{
1264 if ((resolve_mask & QFont::UnderlineResolved) && d->underline == enable)
1265 return;
1266
1267 QFontPrivate::detachButKeepEngineData(font: this);
1268
1269 d->underline = enable;
1270 resolve_mask |= QFont::UnderlineResolved;
1271}
1272
1273/*!
1274 Returns \c true if overline has been set; otherwise returns \c false.
1275
1276 \sa setOverline()
1277*/
1278bool QFont::overline() const
1279{
1280 return d->overline;
1281}
1282
1283/*!
1284 If \a enable is true, sets overline on; otherwise sets overline off.
1285
1286 \sa overline(), QFontInfo
1287*/
1288void QFont::setOverline(bool enable)
1289{
1290 if ((resolve_mask & QFont::OverlineResolved) && d->overline == enable)
1291 return;
1292
1293 QFontPrivate::detachButKeepEngineData(font: this);
1294
1295 d->overline = enable;
1296 resolve_mask |= QFont::OverlineResolved;
1297}
1298
1299/*!
1300 Returns \c true if strikeout has been set; otherwise returns \c false.
1301
1302 \sa setStrikeOut()
1303*/
1304bool QFont::strikeOut() const
1305{
1306 return d->strikeOut;
1307}
1308
1309/*!
1310 If \a enable is true, sets strikeout on; otherwise sets strikeout
1311 off.
1312
1313 \sa strikeOut(), QFontInfo
1314*/
1315void QFont::setStrikeOut(bool enable)
1316{
1317 if ((resolve_mask & QFont::StrikeOutResolved) && d->strikeOut == enable)
1318 return;
1319
1320 QFontPrivate::detachButKeepEngineData(font: this);
1321
1322 d->strikeOut = enable;
1323 resolve_mask |= QFont::StrikeOutResolved;
1324}
1325
1326/*!
1327 Returns \c true if fixed pitch has been set; otherwise returns \c false.
1328
1329 \sa setFixedPitch(), QFontInfo::fixedPitch()
1330*/
1331bool QFont::fixedPitch() const
1332{
1333 return d->request.fixedPitch;
1334}
1335
1336/*!
1337 If \a enable is true, sets fixed pitch on; otherwise sets fixed
1338 pitch off.
1339
1340 \sa fixedPitch(), QFontInfo
1341*/
1342void QFont::setFixedPitch(bool enable)
1343{
1344 if ((resolve_mask & QFont::FixedPitchResolved) && d->request.fixedPitch == enable)
1345 return;
1346
1347 detach();
1348
1349 d->request.fixedPitch = enable;
1350 d->request.ignorePitch = false;
1351 resolve_mask |= QFont::FixedPitchResolved;
1352}
1353
1354/*!
1355 Returns \c true if kerning should be used when drawing text with this font.
1356
1357 \sa setKerning()
1358*/
1359bool QFont::kerning() const
1360{
1361 return d->kerning;
1362}
1363
1364/*!
1365 Enables kerning for this font if \a enable is true; otherwise
1366 disables it. By default, kerning is enabled.
1367
1368 When kerning is enabled, glyph metrics do not add up anymore,
1369 even for Latin text. In other words, the assumption that
1370 width('a') + width('b') is equal to width("ab") is not
1371 necessarily true.
1372
1373 \sa kerning(), QFontMetrics
1374*/
1375void QFont::setKerning(bool enable)
1376{
1377 if ((resolve_mask & QFont::KerningResolved) && d->kerning == enable)
1378 return;
1379
1380 QFontPrivate::detachButKeepEngineData(font: this);
1381
1382 d->kerning = enable;
1383 resolve_mask |= QFont::KerningResolved;
1384}
1385
1386/*!
1387 Returns the StyleStrategy.
1388
1389 The style strategy affects the \l{QFont}{font matching} algorithm.
1390 See \l QFont::StyleStrategy for the list of available strategies.
1391
1392 \sa setStyleHint(), QFont::StyleHint
1393*/
1394QFont::StyleStrategy QFont::styleStrategy() const
1395{
1396 return (StyleStrategy) d->request.styleStrategy;
1397}
1398
1399/*!
1400 Returns the StyleHint.
1401
1402 The style hint affects the \l{QFont#fontmatching}{font matching algorithm}.
1403 See \l QFont::StyleHint for the list of available hints.
1404
1405 \sa setStyleHint(), QFont::StyleStrategy, QFontInfo::styleHint()
1406*/
1407QFont::StyleHint QFont::styleHint() const
1408{
1409 return (StyleHint) d->request.styleHint;
1410}
1411
1412/*!
1413 \enum QFont::StyleHint
1414
1415 Style hints are used by the \l{QFont}{font matching} algorithm to
1416 find an appropriate default family if a selected font family is
1417 not available.
1418
1419 \value AnyStyle leaves the font matching algorithm to choose the
1420 family. This is the default.
1421
1422 \value SansSerif the font matcher prefer sans serif fonts.
1423 \value Helvetica is a synonym for \c SansSerif.
1424
1425 \value Serif the font matcher prefers serif fonts.
1426 \value Times is a synonym for \c Serif.
1427
1428 \value TypeWriter the font matcher prefers fixed pitch fonts.
1429 \value Courier a synonym for \c TypeWriter.
1430
1431 \value OldEnglish the font matcher prefers decorative fonts.
1432 \value Decorative is a synonym for \c OldEnglish.
1433
1434 \value Monospace the font matcher prefers fonts that map to the
1435 CSS generic font-family 'monospace'.
1436
1437 \value Fantasy the font matcher prefers fonts that map to the
1438 CSS generic font-family 'fantasy'.
1439
1440 \value Cursive the font matcher prefers fonts that map to the
1441 CSS generic font-family 'cursive'.
1442
1443 \value System the font matcher prefers system fonts.
1444*/
1445
1446/*!
1447 \enum QFont::StyleStrategy
1448
1449 The style strategy tells the \l{QFont}{font matching} algorithm
1450 what type of fonts should be used to find an appropriate default
1451 family.
1452
1453 The following strategies are available:
1454
1455 \value PreferDefault the default style strategy. It does not prefer
1456 any type of font.
1457 \value PreferBitmap prefers bitmap fonts (as opposed to outline
1458 fonts).
1459 \value PreferDevice prefers device fonts.
1460 \value PreferOutline prefers outline fonts (as opposed to bitmap fonts).
1461 \value ForceOutline forces the use of outline fonts.
1462 \value NoAntialias don't antialias the fonts.
1463 \value NoSubpixelAntialias avoid subpixel antialiasing on the fonts if possible.
1464 \value PreferAntialias antialias if possible.
1465 \value [since 6.8] ContextFontMerging If the selected font does not contain a certain character,
1466 then Qt automatically chooses a similar-looking fallback font that contains the
1467 character. By default this is done on a character-by-character basis. This means that in
1468 certain uncommon cases, multiple fonts may be used to represent one string of text even
1469 if it's in the same script. Setting \c ContextFontMerging will try finding the fallback
1470 font that matches the largest subset of the input string instead. This will be more
1471 expensive for strings where missing glyphs occur, but may give more consistent results.
1472 If \c NoFontMerging is set, then \c ContextFontMerging will have no effect.
1473 \value [since 6.8] PreferTypoLineMetrics For compatibility reasons, OpenType fonts contain
1474 two competing sets of the vertical line metrics that provide the
1475 \l{QFontMetricsF::ascent()}{ascent}, \l{QFontMetricsF::descent()}{descent} and
1476 \l{QFontMetricsF::leading()}{leading} of the font. These are often referred to as the
1477 \l{https://learn.microsoft.com/en-us/typography/opentype/spec/os2#uswinascent}{win}
1478 (Windows) metrics and the
1479 \l{https://learn.microsoft.com/en-us/typography/opentype/spec/os2#sta}{typo}
1480 (typographical) metrics. While the specification recommends using the \c typo metrics for
1481 line spacing, many applications prefer the \c win metrics unless the \c{USE_TYPO_METRICS}
1482 flag is set in the
1483 \l{https://learn.microsoft.com/en-us/typography/opentype/spec/os2#fsselection}{fsSelection}
1484 field of the font. For backwards-compatibility reasons, this is also the case for Qt
1485 applications. This is not an issue for fonts that set the \c{USE_TYPO_METRICS} flag to
1486 indicate that the \c{typo} metrics are valid, nor for fonts where the \c{win} metrics
1487 and \c{typo} metrics match up. However, for certain fonts the \c{win} metrics may be
1488 larger than the preferable line spacing and the \c{USE_TYPO_METRICS} flag may be unset
1489 by mistake. For such fonts, setting \c{PreferTypoLineMetrics} may give superior results.
1490 \value NoFontMerging If the font selected for a certain writing system
1491 does not contain a character requested to draw, then Qt automatically chooses a similar
1492 looking font that contains the character. The NoFontMerging flag disables this feature.
1493 Please note that enabling this flag will not prevent Qt from automatically picking a
1494 suitable font when the selected font does not support the writing system of the text.
1495 \value PreferNoShaping Sometimes, a font will apply complex rules to a set of characters in
1496 order to display them correctly. In some writing systems, such as Brahmic scripts, this is
1497 required in order for the text to be legible, but in e.g. Latin script, it is merely
1498 a cosmetic feature. The PreferNoShaping flag will disable all such features when they
1499 are not required, which will improve performance in most cases (since Qt 5.10).
1500
1501 Any of these may be OR-ed with one of these flags:
1502
1503 \value PreferMatch prefer an exact match. The font matcher will try to
1504 use the exact font size that has been specified.
1505 \value PreferQuality prefer the best quality font. The font matcher
1506 will use the nearest standard point size that the font
1507 supports.
1508*/
1509
1510/*!
1511 Sets the style hint and strategy to \a hint and \a strategy,
1512 respectively.
1513
1514 If these aren't set explicitly the style hint will default to
1515 \c AnyStyle and the style strategy to \c PreferDefault.
1516
1517 Qt does not support style hints on X11 since this information
1518 is not provided by the window system.
1519
1520 \sa StyleHint, styleHint(), StyleStrategy, styleStrategy(), QFontInfo
1521*/
1522void QFont::setStyleHint(StyleHint hint, StyleStrategy strategy)
1523{
1524 if ((resolve_mask & (QFont::StyleHintResolved | QFont::StyleStrategyResolved)) &&
1525 (StyleHint) d->request.styleHint == hint &&
1526 (StyleStrategy) d->request.styleStrategy == strategy)
1527 return;
1528
1529 detach();
1530
1531 d->request.styleHint = hint;
1532 d->request.styleStrategy = strategy;
1533 resolve_mask |= QFont::StyleHintResolved;
1534 resolve_mask |= QFont::StyleStrategyResolved;
1535
1536}
1537
1538/*!
1539 Sets the style strategy for the font to \a s.
1540
1541 \sa QFont::StyleStrategy
1542*/
1543void QFont::setStyleStrategy(StyleStrategy s)
1544{
1545 if ((resolve_mask & QFont::StyleStrategyResolved) &&
1546 s == (StyleStrategy)d->request.styleStrategy)
1547 return;
1548
1549 detach();
1550
1551 d->request.styleStrategy = s;
1552 resolve_mask |= QFont::StyleStrategyResolved;
1553}
1554
1555
1556/*!
1557 \enum QFont::Stretch
1558
1559 Predefined stretch values that follow the CSS naming convention. The higher
1560 the value, the more stretched the text is.
1561
1562 \value [since 5.8] AnyStretch 0 Accept any stretch matched using the other QFont properties
1563 \value UltraCondensed 50
1564 \value ExtraCondensed 62
1565 \value Condensed 75
1566 \value SemiCondensed 87
1567 \value Unstretched 100
1568 \value SemiExpanded 112
1569 \value Expanded 125
1570 \value ExtraExpanded 150
1571 \value UltraExpanded 200
1572
1573 \sa setStretch(), stretch()
1574*/
1575
1576/*!
1577 Returns the stretch factor for the font.
1578
1579 \sa setStretch()
1580 */
1581int QFont::stretch() const
1582{
1583 return d->request.stretch;
1584}
1585
1586/*!
1587 Sets the stretch factor for the font.
1588
1589 The stretch factor matches a condensed or expanded version of the font or
1590 applies a stretch transform that changes the width of all characters
1591 in the font by \a factor percent. For example, setting \a factor to 150
1592 results in all characters in the font being 1.5 times (ie. 150%)
1593 wider. The minimum stretch factor is 1, and the maximum stretch factor
1594 is 4000. The default stretch factor is \c AnyStretch, which will accept
1595 any stretch factor and not apply any transform on the font.
1596
1597 The stretch factor is only applied to outline fonts. The stretch
1598 factor is ignored for bitmap fonts.
1599
1600 \note When matching a font with a native non-default stretch factor,
1601 requesting a stretch of 100 will stretch it back to a medium width font.
1602
1603 \sa stretch(), QFont::Stretch
1604*/
1605void QFont::setStretch(int factor)
1606{
1607 if (factor < 0 || factor > 4000) {
1608 qWarning(msg: "QFont::setStretch: Parameter '%d' out of range", factor);
1609 return;
1610 }
1611
1612 if ((resolve_mask & QFont::StretchResolved) &&
1613 d->request.stretch == (uint)factor)
1614 return;
1615
1616 detach();
1617
1618 d->request.stretch = (uint)factor;
1619 resolve_mask |= QFont::StretchResolved;
1620}
1621
1622/*!
1623 \enum QFont::SpacingType
1624 \since 4.4
1625
1626 \value PercentageSpacing A value of 100 will keep the spacing unchanged; a value of 200 will enlarge the
1627 spacing after a character by the width of the character itself.
1628 \value AbsoluteSpacing A positive value increases the letter spacing by the corresponding pixels; a negative
1629 value decreases the spacing.
1630*/
1631
1632/*!
1633 \since 4.4
1634 Returns the letter spacing for the font.
1635
1636 \sa setLetterSpacing(), letterSpacingType(), setWordSpacing()
1637 */
1638qreal QFont::letterSpacing() const
1639{
1640 return d->letterSpacing.toReal();
1641}
1642
1643/*!
1644 \since 4.4
1645 Sets the letter spacing for the font to \a spacing and the type
1646 of spacing to \a type.
1647
1648 Letter spacing changes the default spacing between individual
1649 letters in the font. The spacing between the letters can be
1650 made smaller as well as larger either in percentage of the
1651 character width or in pixels, depending on the selected spacing type.
1652
1653 \sa letterSpacing(), letterSpacingType(), setWordSpacing()
1654*/
1655void QFont::setLetterSpacing(SpacingType type, qreal spacing)
1656{
1657 const QFixed newSpacing = QFixed::fromReal(r: spacing);
1658 const bool absoluteSpacing = type == AbsoluteSpacing;
1659 if ((resolve_mask & QFont::LetterSpacingResolved) &&
1660 d->letterSpacingIsAbsolute == absoluteSpacing &&
1661 d->letterSpacing == newSpacing)
1662 return;
1663
1664 QFontPrivate::detachButKeepEngineData(font: this);
1665
1666 d->letterSpacing = newSpacing;
1667 d->letterSpacingIsAbsolute = absoluteSpacing;
1668 resolve_mask |= QFont::LetterSpacingResolved;
1669}
1670
1671/*!
1672 \since 4.4
1673 Returns the spacing type used for letter spacing.
1674
1675 \sa letterSpacing(), setLetterSpacing(), setWordSpacing()
1676*/
1677QFont::SpacingType QFont::letterSpacingType() const
1678{
1679 return d->letterSpacingIsAbsolute ? AbsoluteSpacing : PercentageSpacing;
1680}
1681
1682/*!
1683 \since 4.4
1684 Returns the word spacing for the font.
1685
1686 \sa setWordSpacing(), setLetterSpacing()
1687 */
1688qreal QFont::wordSpacing() const
1689{
1690 return d->wordSpacing.toReal();
1691}
1692
1693/*!
1694 \since 4.4
1695 Sets the word spacing for the font to \a spacing.
1696
1697 Word spacing changes the default spacing between individual
1698 words. A positive value increases the word spacing
1699 by a corresponding amount of pixels, while a negative value
1700 decreases the inter-word spacing accordingly.
1701
1702 Word spacing will not apply to writing systems, where indiviaul
1703 words are not separated by white space.
1704
1705 \sa wordSpacing(), setLetterSpacing()
1706*/
1707void QFont::setWordSpacing(qreal spacing)
1708{
1709 const QFixed newSpacing = QFixed::fromReal(r: spacing);
1710 if ((resolve_mask & QFont::WordSpacingResolved) &&
1711 d->wordSpacing == newSpacing)
1712 return;
1713
1714 QFontPrivate::detachButKeepEngineData(font: this);
1715
1716 d->wordSpacing = newSpacing;
1717 resolve_mask |= QFont::WordSpacingResolved;
1718}
1719
1720/*!
1721 \enum QFont::Capitalization
1722 \since 4.4
1723
1724 Rendering option for text this font applies to.
1725
1726
1727 \value MixedCase This is the normal text rendering option where no capitalization change is applied.
1728 \value AllUppercase This alters the text to be rendered in all uppercase type.
1729 \value AllLowercase This alters the text to be rendered in all lowercase type.
1730 \value SmallCaps This alters the text to be rendered in small-caps type.
1731 \value Capitalize This alters the text to be rendered with the first character of each word as an uppercase character.
1732*/
1733
1734/*!
1735 \since 4.4
1736 Sets the capitalization of the text in this font to \a caps.
1737
1738 A font's capitalization makes the text appear in the selected capitalization mode.
1739
1740 \sa capitalization()
1741*/
1742void QFont::setCapitalization(Capitalization caps)
1743{
1744 if ((resolve_mask & QFont::CapitalizationResolved) &&
1745 capitalization() == caps)
1746 return;
1747
1748 QFontPrivate::detachButKeepEngineData(font: this);
1749
1750 d->capital = caps;
1751 resolve_mask |= QFont::CapitalizationResolved;
1752}
1753
1754/*!
1755 \since 4.4
1756 Returns the current capitalization type of the font.
1757
1758 \sa setCapitalization()
1759*/
1760QFont::Capitalization QFont::capitalization() const
1761{
1762 return static_cast<QFont::Capitalization> (d->capital);
1763}
1764
1765/*!
1766 Returns \c true if a window system font exactly matching the settings
1767 of this font is available.
1768
1769 \sa QFontInfo
1770*/
1771bool QFont::exactMatch() const
1772{
1773 QFontEngine *engine = d->engineForScript(script: QChar::Script_Common);
1774 Q_ASSERT(engine != nullptr);
1775 return d->request.exactMatch(other: engine->fontDef);
1776}
1777
1778/*!
1779 Returns \c true if this font is equal to \a f; otherwise returns
1780 false.
1781
1782 Two QFonts are considered equal if their font attributes are
1783 equal.
1784
1785 \sa operator!=(), isCopyOf()
1786*/
1787bool QFont::operator==(const QFont &f) const
1788{
1789 return (f.d == d
1790 || (f.d->request == d->request
1791 && f.d->request.pointSize == d->request.pointSize
1792 && f.d->underline == d->underline
1793 && f.d->overline == d->overline
1794 && f.d->strikeOut == d->strikeOut
1795 && f.d->kerning == d->kerning
1796 && f.d->capital == d->capital
1797 && f.d->letterSpacingIsAbsolute == d->letterSpacingIsAbsolute
1798 && f.d->letterSpacing == d->letterSpacing
1799 && f.d->wordSpacing == d->wordSpacing
1800 && f.d->features == d->features
1801 ));
1802}
1803
1804
1805/*!
1806 Provides an arbitrary comparison of this font and font \a f.
1807 All that is guaranteed is that the operator returns \c false if both
1808 fonts are equal and that (f1 \< f2) == !(f2 \< f1) if the fonts
1809 are not equal.
1810
1811 This function is useful in some circumstances, for example if you
1812 want to use QFont objects as keys in a QMap.
1813
1814 \sa operator==(), operator!=(), isCopyOf()
1815*/
1816bool QFont::operator<(const QFont &f) const
1817{
1818 if (f.d == d) return false;
1819 // the < operator for fontdefs ignores point sizes.
1820 const QFontDef &r1 = f.d->request;
1821 const QFontDef &r2 = d->request;
1822 if (r1.pointSize != r2.pointSize) return r1.pointSize < r2.pointSize;
1823 if (r1.pixelSize != r2.pixelSize) return r1.pixelSize < r2.pixelSize;
1824 if (r1.weight != r2.weight) return r1.weight < r2.weight;
1825 if (r1.style != r2.style) return r1.style < r2.style;
1826 if (r1.stretch != r2.stretch) return r1.stretch < r2.stretch;
1827 if (r1.styleHint != r2.styleHint) return r1.styleHint < r2.styleHint;
1828 if (r1.styleStrategy != r2.styleStrategy) return r1.styleStrategy < r2.styleStrategy;
1829 if (r1.families != r2.families) return r1.families < r2.families;
1830 if (f.d->capital != d->capital) return f.d->capital < d->capital;
1831
1832 if (f.d->letterSpacingIsAbsolute != d->letterSpacingIsAbsolute) return f.d->letterSpacingIsAbsolute < d->letterSpacingIsAbsolute;
1833 if (f.d->letterSpacing != d->letterSpacing) return f.d->letterSpacing < d->letterSpacing;
1834 if (f.d->wordSpacing != d->wordSpacing) return f.d->wordSpacing < d->wordSpacing;
1835
1836 int f1attrs = (f.d->underline << 3) + (f.d->overline << 2) + (f.d->strikeOut<<1) + f.d->kerning;
1837 int f2attrs = (d->underline << 3) + (d->overline << 2) + (d->strikeOut<<1) + d->kerning;
1838 if (f1attrs != f2attrs) return f1attrs < f2attrs;
1839
1840 if (d->features.size() != f.d->features.size())
1841 return f.d->features.size() < d->features.size();
1842
1843 {
1844 auto it = d->features.constBegin();
1845 auto jt = f.d->features.constBegin();
1846 for (; it != d->features.constEnd(); ++it, ++jt) {
1847 if (it.key() != jt.key())
1848 return jt.key() < it.key();
1849 if (it.value() != jt.value())
1850 return jt.value() < it.value();
1851 }
1852 }
1853
1854 if (r1.variableAxisValues.size() != r2.variableAxisValues.size())
1855 return r1.variableAxisValues.size() < r2.variableAxisValues.size();
1856
1857 {
1858 auto it = r1.variableAxisValues.constBegin();
1859 auto jt = r2.variableAxisValues.constBegin();
1860 for (; it != r1.variableAxisValues.constEnd(); ++it, ++jt) {
1861 if (it.key() != jt.key())
1862 return jt.key() < it.key();
1863 if (it.value() != jt.value())
1864 return jt.value() < it.value();
1865 }
1866 }
1867
1868 return false;
1869}
1870
1871
1872/*!
1873 Returns \c true if this font is different from \a f; otherwise
1874 returns \c false.
1875
1876 Two QFonts are considered to be different if their font attributes
1877 are different.
1878
1879 \sa operator==()
1880*/
1881bool QFont::operator!=(const QFont &f) const
1882{
1883 return !(operator==(f));
1884}
1885
1886/*!
1887 Returns the font as a QVariant
1888*/
1889QFont::operator QVariant() const
1890{
1891 return QVariant::fromValue(value: *this);
1892}
1893
1894/*!
1895 Returns \c true if this font and \a f are copies of each other, i.e.
1896 one of them was created as a copy of the other and neither has
1897 been modified since. This is much stricter than equality.
1898
1899 \sa operator=(), operator==()
1900*/
1901bool QFont::isCopyOf(const QFont & f) const
1902{
1903 return d == f.d;
1904}
1905
1906/*!
1907 Returns a new QFont that has attributes copied from \a other that
1908 have not been previously set on this font.
1909*/
1910QFont QFont::resolve(const QFont &other) const
1911{
1912 if (resolve_mask == 0 || (resolve_mask == other.resolve_mask && *this == other)) {
1913 QFont o(other);
1914 o.resolve_mask = resolve_mask;
1915 return o;
1916 }
1917
1918 QFont font(*this);
1919 font.detach();
1920 font.d->resolve(mask: resolve_mask, other: other.d.data());
1921
1922 return font;
1923}
1924
1925/*!
1926 \fn uint QFont::resolveMask() const
1927 \internal
1928*/
1929
1930/*!
1931 \fn void QFont::setResolveMask(uint mask)
1932 \internal
1933*/
1934
1935
1936/*****************************************************************************
1937 QFont substitution management
1938 *****************************************************************************/
1939
1940typedef QHash<QString, QStringList> QFontSubst;
1941Q_GLOBAL_STATIC(QFontSubst, globalFontSubst)
1942
1943/*!
1944 Returns the first family name to be used whenever \a familyName is
1945 specified. The lookup is case insensitive.
1946
1947 If there is no substitution for \a familyName, \a familyName is
1948 returned.
1949
1950 To obtain a list of substitutions use substitutes().
1951
1952 \sa setFamily(), insertSubstitutions(), insertSubstitution(), removeSubstitutions()
1953*/
1954QString QFont::substitute(const QString &familyName)
1955{
1956 QFontSubst *fontSubst = globalFontSubst();
1957 Q_ASSERT(fontSubst != nullptr);
1958 QFontSubst::ConstIterator it = fontSubst->constFind(key: familyName.toLower());
1959 if (it != fontSubst->constEnd() && !(*it).isEmpty())
1960 return (*it).first();
1961
1962 return familyName;
1963}
1964
1965
1966/*!
1967 Returns a list of family names to be used whenever \a familyName
1968 is specified. The lookup is case insensitive.
1969
1970 If there is no substitution for \a familyName, an empty list is
1971 returned.
1972
1973 \sa substitute(), insertSubstitutions(), insertSubstitution(), removeSubstitutions()
1974 */
1975QStringList QFont::substitutes(const QString &familyName)
1976{
1977 QFontSubst *fontSubst = globalFontSubst();
1978 Q_ASSERT(fontSubst != nullptr);
1979 return fontSubst->value(key: familyName.toLower(), defaultValue: QStringList());
1980}
1981
1982
1983/*!
1984 Inserts \a substituteName into the substitution
1985 table for the family \a familyName.
1986
1987 After substituting a font, trigger the updating of the font by destroying
1988 and re-creating all QFont objects.
1989
1990 \sa insertSubstitutions(), removeSubstitutions(), substitutions(), substitute(), substitutes()
1991*/
1992void QFont::insertSubstitution(const QString &familyName,
1993 const QString &substituteName)
1994{
1995 QFontSubst *fontSubst = globalFontSubst();
1996 Q_ASSERT(fontSubst != nullptr);
1997 QStringList &list = (*fontSubst)[familyName.toLower()];
1998 QString s = substituteName.toLower();
1999 if (!list.contains(str: s))
2000 list.append(t: s);
2001}
2002
2003
2004/*!
2005 Inserts the list of families \a substituteNames into the
2006 substitution list for \a familyName.
2007
2008 After substituting a font, trigger the updating of the font by destroying
2009 and re-creating all QFont objects.
2010
2011
2012 \sa insertSubstitution(), removeSubstitutions(), substitutions(), substitute()
2013*/
2014void QFont::insertSubstitutions(const QString &familyName,
2015 const QStringList &substituteNames)
2016{
2017 QFontSubst *fontSubst = globalFontSubst();
2018 Q_ASSERT(fontSubst != nullptr);
2019 QStringList &list = (*fontSubst)[familyName.toLower()];
2020 for (const QString &substituteName : substituteNames) {
2021 const QString lowerSubstituteName = substituteName.toLower();
2022 if (!list.contains(str: lowerSubstituteName))
2023 list.append(t: lowerSubstituteName);
2024 }
2025}
2026
2027/*!
2028 Removes all the substitutions for \a familyName.
2029
2030 \sa insertSubstitutions(), insertSubstitution(), substitutions(), substitute()
2031 \since 5.0
2032*/
2033void QFont::removeSubstitutions(const QString &familyName)
2034{
2035 QFontSubst *fontSubst = globalFontSubst();
2036 Q_ASSERT(fontSubst != nullptr);
2037 fontSubst->remove(key: familyName.toLower());
2038}
2039
2040/*!
2041 Returns a sorted list of substituted family names.
2042
2043 \sa insertSubstitution(), removeSubstitutions(), substitute()
2044*/
2045QStringList QFont::substitutions()
2046{
2047 QFontSubst *fontSubst = globalFontSubst();
2048 Q_ASSERT(fontSubst != nullptr);
2049 QStringList ret = fontSubst->keys();
2050
2051 ret.sort();
2052 return ret;
2053}
2054
2055#ifndef QT_NO_DATASTREAM
2056/* \internal
2057 Internal function. Converts boolean font settings to an unsigned
2058 8-bit number. Used for serialization etc.
2059*/
2060static quint8 get_font_bits(int version, const QFontPrivate *f)
2061{
2062 Q_ASSERT(f != nullptr);
2063 quint8 bits = 0;
2064 if (f->request.style)
2065 bits |= 0x01;
2066 if (f->underline)
2067 bits |= 0x02;
2068 if (f->overline)
2069 bits |= 0x40;
2070 if (f->strikeOut)
2071 bits |= 0x04;
2072 if (f->request.fixedPitch)
2073 bits |= 0x08;
2074 // if (f.hintSetByUser)
2075 // bits |= 0x10;
2076 if (version >= QDataStream::Qt_4_0) {
2077 if (f->kerning)
2078 bits |= 0x10;
2079 }
2080 if (f->request.style == QFont::StyleOblique)
2081 bits |= 0x80;
2082 return bits;
2083}
2084
2085static quint8 get_extended_font_bits(const QFontPrivate *f)
2086{
2087 Q_ASSERT(f != nullptr);
2088 quint8 bits = 0;
2089 if (f->request.ignorePitch)
2090 bits |= 0x01;
2091 if (f->letterSpacingIsAbsolute)
2092 bits |= 0x02;
2093 return bits;
2094}
2095
2096/* \internal
2097 Internal function. Sets boolean font settings from an unsigned
2098 8-bit number. Used for serialization etc.
2099*/
2100static void set_font_bits(int version, quint8 bits, QFontPrivate *f)
2101{
2102 Q_ASSERT(f != nullptr);
2103 f->request.style = (bits & 0x01) != 0 ? QFont::StyleItalic : QFont::StyleNormal;
2104 f->underline = (bits & 0x02) != 0;
2105 f->overline = (bits & 0x40) != 0;
2106 f->strikeOut = (bits & 0x04) != 0;
2107 f->request.fixedPitch = (bits & 0x08) != 0;
2108 // f->hintSetByUser = (bits & 0x10) != 0;
2109 if (version >= QDataStream::Qt_4_0)
2110 f->kerning = (bits & 0x10) != 0;
2111 if ((bits & 0x80) != 0)
2112 f->request.style = QFont::StyleOblique;
2113}
2114
2115static void set_extended_font_bits(quint8 bits, QFontPrivate *f)
2116{
2117 Q_ASSERT(f != nullptr);
2118 f->request.ignorePitch = (bits & 0x01) != 0;
2119 f->letterSpacingIsAbsolute = (bits & 0x02) != 0;
2120}
2121#endif
2122
2123/*!
2124 Returns the font's key, a textual representation of a font. It is
2125 typically used as the key for a cache or dictionary of fonts.
2126
2127 \sa QMap
2128*/
2129QString QFont::key() const
2130{
2131 return toString();
2132}
2133
2134/*!
2135 Returns a description of the font. The description is a
2136 comma-separated list of the attributes, perfectly suited for use
2137 in QSettings, and consists of the following:
2138
2139 \list
2140 \li Font family
2141 \li Point size
2142 \li Pixel size
2143 \li Style hint
2144 \li Font weight
2145 \li Font style
2146 \li Underline
2147 \li Strike out
2148 \li Fixed pitch
2149 \li Always \e{0}
2150 \li Capitalization
2151 \li Letter spacing
2152 \li Word spacing
2153 \li Stretch
2154 \li Style strategy
2155 \li Font style (omitted when unavailable)
2156 \endlist
2157
2158 \sa fromString()
2159 */
2160QString QFont::toString() const
2161{
2162 const QChar comma(u',');
2163 QString fontDescription = family() + comma +
2164 QString::number( pointSizeF()) + comma +
2165 QString::number( pixelSize()) + comma +
2166 QString::number((int) styleHint()) + comma +
2167 QString::number( weight()) + comma +
2168 QString::number((int) style()) + comma +
2169 QString::number((int) underline()) + comma +
2170 QString::number((int) strikeOut()) + comma +
2171 QString::number((int)fixedPitch()) + comma +
2172 QString::number((int) false) + comma +
2173 QString::number((int)capitalization()) + comma +
2174 QString::number((int)letterSpacingType()) + comma +
2175 QString::number(letterSpacing()) + comma +
2176 QString::number(wordSpacing()) + comma +
2177 QString::number(stretch()) + comma +
2178 QString::number((int)styleStrategy());
2179
2180 QString fontStyle = styleName();
2181 if (!fontStyle.isEmpty())
2182 fontDescription += comma + fontStyle;
2183
2184 return fontDescription;
2185}
2186
2187/*!
2188 Returns the hash value for \a font. If specified, \a seed is used
2189 to initialize the hash.
2190
2191 \relates QFont
2192 \since 5.3
2193*/
2194size_t qHash(const QFont &font, size_t seed) noexcept
2195{
2196 return qHash(fd: QFontPrivate::get(font)->request, seed);
2197}
2198
2199
2200/*!
2201 Sets this font to match the description \a descrip. The description
2202 is a comma-separated list of the font attributes, as returned by
2203 toString().
2204
2205 \sa toString()
2206 */
2207bool QFont::fromString(const QString &descrip)
2208{
2209 const auto sr = QStringView(descrip).trimmed();
2210 const auto l = sr.split(sep: u',');
2211 const int count = l.size();
2212 if (!count || (count > 2 && count < 9) || count == 9 || count > 17 ||
2213 l.first().isEmpty()) {
2214 qWarning(msg: "QFont::fromString: Invalid description '%s'",
2215 descrip.isEmpty() ? "(empty)" : descrip.toLatin1().data());
2216 return false;
2217 }
2218
2219 setFamily(l[0].toString());
2220 if (count > 1 && l[1].toDouble() > 0.0)
2221 setPointSizeF(l[1].toDouble());
2222 if (count == 9) {
2223 setStyleHint(hint: (StyleHint) l[2].toInt());
2224 setWeight(QFont::Weight(l[3].toInt()));
2225 setItalic(l[4].toInt());
2226 setUnderline(l[5].toInt());
2227 setStrikeOut(l[6].toInt());
2228 setFixedPitch(l[7].toInt());
2229 } else if (count >= 10) {
2230 if (l[2].toInt() > 0)
2231 setPixelSize(l[2].toInt());
2232 setStyleHint(hint: (StyleHint) l[3].toInt());
2233 if (count >= 16)
2234 setWeight(QFont::Weight(l[4].toInt()));
2235 else
2236 setWeight(QFont::Weight(qt_legacyToOpenTypeWeight(weight: l[4].toInt())));
2237 setStyle((QFont::Style)l[5].toInt());
2238 setUnderline(l[6].toInt());
2239 setStrikeOut(l[7].toInt());
2240 setFixedPitch(l[8].toInt());
2241 if (count >= 16) {
2242 setCapitalization((Capitalization)l[10].toInt());
2243 setLetterSpacing(type: (SpacingType)l[11].toInt(), spacing: l[12].toDouble());
2244 setWordSpacing(l[13].toDouble());
2245 setStretch(l[14].toInt());
2246 setStyleStrategy((StyleStrategy)l[15].toInt());
2247 }
2248 if (count == 11 || count == 17)
2249 d->request.styleName = l[count - 1].toString();
2250 else
2251 d->request.styleName.clear();
2252 }
2253
2254 if (count >= 9 && !d->request.fixedPitch) // assume 'false' fixedPitch equals default
2255 d->request.ignorePitch = true;
2256
2257 return true;
2258}
2259
2260/*! \fn void QFont::initialize()
2261 \internal
2262
2263 Internal function that initializes the font system. The font cache
2264 and font dict do not alloc the keys. The key is a QString which is
2265 shared between QFontPrivate and QXFontName.
2266*/
2267void QFont::initialize()
2268{
2269}
2270
2271/*! \fn void QFont::cleanup()
2272 \internal
2273
2274 Internal function that cleans up the font system.
2275*/
2276void QFont::cleanup()
2277{
2278 QFontCache::cleanup();
2279}
2280
2281/*! \internal
2282
2283 Internal function that dumps font cache statistics.
2284*/
2285void QFont::cacheStatistics()
2286{
2287}
2288
2289/*!
2290 \class QFont::Tag
2291 \brief The QFont::Tag type provides access to advanced font features.
2292 \since 6.7
2293 \inmodule QtGui
2294
2295 QFont provides access to advanced features when shaping text. A feature is defined
2296 by a tag, which can be represented as a four-character string, or as a 32bit integer
2297 value. This type represents such a tag in a type-safe way. It can be constructed from
2298 a four-character, 8bit string literal, or from a corresponding 32bit integer value.
2299 Using a shorter or longer string literal will result in a compile-time error.
2300
2301 \code
2302 QFont font;
2303 // Correct
2304 font.setFeature("frac");
2305
2306 // Wrong - won't compile
2307 font.setFeature("fraction");
2308
2309 // Wrong - will produce runtime warning and fail
2310 font.setFeature(u"fraction"_s);
2311 \endcode
2312
2313 The named constructors allow to create a tag from an 32bit integer or string value,
2314 and will return a \c std::nullopt when the input is invalid.
2315
2316 \sa QFont::setFeature(), QFont::featureTags()
2317*/
2318
2319/*!
2320 \fn QFont::Tag::Tag()
2321
2322 Default constructor, producing an invalid tag.
2323*/
2324
2325/*!
2326 \fn template <size_t N> QFont::Tag::Tag(const char (&str)[N]) noexcept
2327
2328 Constructs a tag from a string literal, \a str. The literal must be exactly four
2329 characters long.
2330
2331 \code
2332 font.setFeature("frac", 1);
2333 \endcode
2334
2335 \sa fromString(), fromValue()
2336*/
2337
2338/*!
2339 \fn bool QFont::Tag::comparesEqual(const QFont::Tag &lhs, const QFont::Tag &rhs) noexcept
2340 \fn Qt::strong_ordering QFont::Tag::compareThreeWay(const QFont::Tag &lhs, const QFont::Tag &rhs) noexcept
2341
2342 Compare \a lhs with \a rhs for equality and ordering.
2343*/
2344
2345/*!
2346 \fn size_t QFont::Tag::qHash(QFont::Tag key, size_t seed) noexcept
2347
2348 Returns the hash value for \a key, using \a seed to seed the calculation.
2349*/
2350
2351/*!
2352 \fn quint32 QFont::Tag::value() const noexcept
2353
2354 Returns the numerical value of this tag.
2355
2356 \sa isValid(), fromValue()
2357*/
2358
2359/*!
2360 \fn bool QFont::Tag::isValid() const noexcept
2361
2362 Returns whether the tag is valid. A tag is valid if its value is not zero.
2363
2364 \sa value(), fromValue(), fromString()
2365*/
2366
2367/*!
2368 \fn QByteArray QFont::Tag::toString() const noexcept
2369
2370 Returns the string representation of this tag as a byte array.
2371
2372 \sa fromString()
2373*/
2374
2375/*!
2376 \fn std::optional<QFont::Tag> QFont::Tag::fromValue(quint32 value) noexcept
2377
2378 Returns a tag constructed from \a value, or \c std::nullopt if the tag produced
2379 would be invalid.
2380
2381 \sa isValid()
2382*/
2383
2384/*!
2385 Returns a tag constructed from the string in \a view. The string must be exactly
2386 four characters long.
2387
2388 Returns \c std::nullopt if the input is not four characters long, or if the tag
2389 produced would be invalid.
2390
2391 \sa isValid(), fromValue()
2392*/
2393std::optional<QFont::Tag> QFont::Tag::fromString(QAnyStringView view) noexcept
2394{
2395 if (view.size() != 4) {
2396 qWarning(msg: "The tag name must be exactly 4 characters long!");
2397 return std::nullopt;
2398 }
2399 const QFont::Tag maybeTag = view.visit(v: [](auto view) {
2400 using CharType = decltype(view.at(0));
2401 if constexpr (std::is_same_v<CharType, char>) {
2402 const char bytes[5] = { view.at(0), view.at(1), view.at(2), view.at(3), 0 };
2403 return Tag(bytes);
2404 } else {
2405 const char bytes[5] = { view.at(0).toLatin1(), view.at(1).toLatin1(),
2406 view.at(2).toLatin1(), view.at(3).toLatin1(), 0 };
2407 return Tag(bytes);
2408 }
2409 });
2410 return maybeTag.isValid() ? std::optional<Tag>(maybeTag) : std::nullopt;
2411}
2412
2413/*!
2414 \fn QDataStream &operator<<(QDataStream &, QFont::Tag)
2415 \fn QDataStream &operator>>(QDataStream &, QFont::Tag &)
2416 \relates QFont::Tag
2417
2418 Data stream operators for QFont::Tag.
2419*/
2420
2421/*!
2422 \since 6.7
2423
2424 Applies a \a value to the variable axis corresponding to \a tag.
2425
2426 Variable fonts provide a way to store multiple variations (with different weights, widths
2427 or styles) in the same font file. The variations are given as floating point values for
2428 a pre-defined set of parameters, called "variable axes". Specific instances are typically
2429 given names by the font designer, and, in Qt, these can be selected using setStyleName()
2430 just like traditional sub-families.
2431
2432 In some cases, it is also useful to provide arbitrary values for the different axes. For
2433 instance, if a font has a Regular and Bold sub-family, you may want a weight in-between these.
2434 You could then manually request this by supplying a custom value for the "wght" axis in the
2435 font.
2436
2437 \code
2438 QFont font;
2439 font.setVariableAxis("wght", (QFont::Normal + QFont::Bold) / 2.0f);
2440 \endcode
2441
2442 If the "wght" axis is supported by the font and the given value is within its defined range,
2443 a font corresponding to the weight 550.0 will be provided.
2444
2445 There are a few standard axes than many fonts provide, such as "wght" (weight), "wdth" (width),
2446 "ital" (italic) and "opsz" (optical size). They each have indivdual ranges defined in the font
2447 itself. For instance, "wght" may span from 100 to 900 (QFont::Thin to QFont::Black) whereas
2448 "ital" can span from 0 to 1 (from not italic to fully italic).
2449
2450 A font may also choose to define custom axes; the only limitation is that the name has to
2451 meet the requirements for a QFont::Tag (sequence of four latin-1 characters.)
2452
2453 By default, no variable axes are set.
2454
2455 \note On Windows, variable axes are not supported if the optional GDI font backend is in use.
2456
2457 \sa unsetVariableAxis
2458 */
2459void QFont::setVariableAxis(Tag tag, float value)
2460{
2461 if (tag.isValid()) {
2462 if (resolve_mask & QFont::VariableAxesResolved && d->hasVariableAxis(tag, value))
2463 return;
2464
2465 detach();
2466
2467 d->setVariableAxis(tag, value);
2468 resolve_mask |= QFont::VariableAxesResolved;
2469 }
2470}
2471
2472/*!
2473 \since 6.7
2474
2475 Unsets a previously set variable axis value given by \a tag.
2476
2477 \note If no value has previously been given for this tag, the QFont will still consider its
2478 variable axes as set when resolving against other QFont values.
2479
2480 \sa setVariableAxis
2481*/
2482void QFont::unsetVariableAxis(Tag tag)
2483{
2484 if (tag.isValid()) {
2485 detach();
2486
2487 d->unsetVariableAxis(tag);
2488 resolve_mask |= QFont::VariableAxesResolved;
2489 }
2490}
2491
2492/*!
2493 \since 6.7
2494
2495 Returns a list of tags for all variable axes currently set on this QFont.
2496
2497 See \l{QFont::}{setVariableAxis()} for more details on variable axes.
2498
2499 \sa QFont::Tag, setVariableAxis(), unsetVariableAxis(), isVariableAxisSet(), clearVariableAxes()
2500*/
2501QList<QFont::Tag> QFont::variableAxisTags() const
2502{
2503 return d->request.variableAxisValues.keys();
2504}
2505
2506/*!
2507 \since 6.7
2508
2509 Returns the value set for a specific variable axis \a tag. If the tag has not been set, 0.0 will
2510 be returned instead.
2511
2512 See \l{QFont::}{setVariableAxis()} for more details on variable axes.
2513
2514 \sa QFont::Tag, setVariableAxis(), unsetVariableAxis(), isVariableAxisSet(), clearVariableAxes()
2515*/
2516float QFont::variableAxisValue(Tag tag) const
2517{
2518 return d->request.variableAxisValues.value(key: tag);
2519}
2520
2521/*!
2522 \since 6.7
2523
2524 Returns true if a value for the variable axis given by \a tag has been set on the QFont,
2525 otherwise returns false.
2526
2527 See \l{QFont::}{setVariableAxis()} for more details on font variable axes.
2528
2529 \sa QFont::Tag, setVariableAxis(), unsetVariableAxis(), variableAxisValue(), clearVariableAxes()
2530*/
2531bool QFont::isVariableAxisSet(Tag tag) const
2532{
2533 return d->request.variableAxisValues.contains(key: tag);
2534}
2535
2536/*!
2537 \since 6.7
2538
2539 Clears any previously set variable axis values on the QFont.
2540
2541 See \l{QFont::}{setVariableAxis()} for more details on variable axes.
2542
2543 \sa QFont::Tag, setVariableAxis(), unsetVariableAxis(), isVariableAxisSet(), variableAxisValue()
2544*/
2545void QFont::clearVariableAxes()
2546{
2547 if (d->request.variableAxisValues.isEmpty())
2548 return;
2549
2550 detach();
2551 d->request.variableAxisValues.clear();
2552}
2553
2554
2555/*!
2556 \since 6.7
2557 \overload
2558
2559 Applies an integer value to the typographical feature specified by \a tag when shaping the
2560 text. This provides advanced access to the font shaping process, and can be used to support
2561 font features that are otherwise not covered in the API.
2562
2563 The feature is specified by a \l{QFont::Tag}{tag}, which is typically encoded from the
2564 four-character feature name in the font feature map.
2565
2566 This integer \a value passed along with the tag in most cases represents a boolean value: A zero
2567 value means the feature is disabled, and a non-zero value means it is enabled. For certain
2568 font features, however, it may have other interpretations. For example, when applied to the
2569 \c salt feature, the value is an index that specifies the stylistic alternative to use.
2570
2571 For example, the \c frac font feature will convert diagonal fractions separated with a slash
2572 (such as \c 1/2) with a different representation. Typically this will involve baking the full
2573 fraction into a single character width (such as \c ½).
2574
2575 If a font supports the \c frac feature, then it can be enabled in the shaper by setting
2576 \c{features["frac"] = 1} in the font feature map.
2577
2578 \note By default, Qt will enable and disable certain font features based on other font
2579 properties. In particular, the \c kern feature will be enabled/disabled depending on the
2580 \l kerning() property of the QFont. In addition, all ligature features
2581 (\c liga, \c clig, \c dlig, \c hlig) will be disabled if a \l letterSpacing() is applied,
2582 but only for writing systems where the use of ligature is cosmetic. For writing systems where
2583 ligatures are required, the features will remain in their default state. The values set using
2584 setFeature() and related functions will override the default behavior. If, for instance,
2585 the feature "kern" is set to 1, then kerning will always be enabled, regardless of whether the
2586 kerning property is set to false. Similarly, if it is set to 0, then it will always be disabled.
2587 To reset a font feature to its default behavior, you can unset it using unsetFeature().
2588
2589 \sa QFont::Tag, clearFeatures(), setFeature(), unsetFeature(), featureTags()
2590*/
2591void QFont::setFeature(Tag tag, quint32 value)
2592{
2593 if (tag.isValid()) {
2594 d->detachButKeepEngineData(font: this);
2595 d->setFeature(tag, value);
2596 resolve_mask |= QFont::FeaturesResolved;
2597 }
2598}
2599
2600/*!
2601 \since 6.7
2602 \overload
2603
2604 Unsets the \a tag from the map of explicitly enabled/disabled features.
2605
2606 \note Even if the feature has not previously been added, this will mark the font features map
2607 as modified in this QFont, so that it will take precedence when resolving against other fonts.
2608
2609 Unsetting an existing feature on the QFont reverts behavior to the default.
2610
2611 See \l setFeature() for more details on font features.
2612
2613 \sa QFont::Tag, clearFeatures(), setFeature(), featureTags(), featureValue()
2614*/
2615void QFont::unsetFeature(Tag tag)
2616{
2617 if (tag.isValid()) {
2618 d->detachButKeepEngineData(font: this);
2619 d->unsetFeature(tag);
2620 resolve_mask |= QFont::FeaturesResolved;
2621 }
2622}
2623
2624/*!
2625 \since 6.7
2626
2627 Returns a list of tags for all font features currently set on this QFont.
2628
2629 See \l{QFont::}{setFeature()} for more details on font features.
2630
2631 \sa QFont::Tag, setFeature(), unsetFeature(), isFeatureSet(), clearFeatures()
2632*/
2633QList<QFont::Tag> QFont::featureTags() const
2634{
2635 return d->features.keys();
2636}
2637
2638/*!
2639 \since 6.7
2640
2641 Returns the value set for a specific feature \a tag. If the tag has not been set, 0 will be
2642 returned instead.
2643
2644 See \l{QFont::}{setFeature()} for more details on font features.
2645
2646 \sa QFont::Tag, setFeature(), unsetFeature(), featureTags(), isFeatureSet()
2647*/
2648quint32 QFont::featureValue(Tag tag) const
2649{
2650 return d->features.value(key: tag);
2651}
2652
2653/*!
2654 \since 6.7
2655
2656 Returns true if a value for the feature given by \a tag has been set on the QFont, otherwise
2657 returns false.
2658
2659 See \l{QFont::}{setFeature()} for more details on font features.
2660
2661 \sa QFont::Tag, setFeature(), unsetFeature(), featureTags(), featureValue()
2662*/
2663bool QFont::isFeatureSet(Tag tag) const
2664{
2665 return d->features.contains(key: tag);
2666}
2667
2668/*!
2669 \since 6.7
2670
2671 Clears any previously set features on the QFont.
2672
2673 See \l{QFont::}{setFeature()} for more details on font features.
2674
2675 \sa QFont::Tag, setFeature(), unsetFeature(), featureTags(), featureValue()
2676*/
2677void QFont::clearFeatures()
2678{
2679 if (d->features.isEmpty())
2680 return;
2681
2682 d->detachButKeepEngineData(font: this);
2683 d->features.clear();
2684}
2685
2686extern QStringList qt_fallbacksForFamily(const QString &family, QFont::Style style,
2687 QFont::StyleHint styleHint, QChar::Script script);
2688
2689/*!
2690 \fn QString QFont::defaultFamily() const
2691
2692 Returns the family name that corresponds to the current style
2693 hint.
2694
2695 \sa StyleHint, styleHint(), setStyleHint()
2696*/
2697QString QFont::defaultFamily() const
2698{
2699 const QStringList fallbacks = qt_fallbacksForFamily(family: QString(), style: QFont::StyleNormal
2700 , styleHint: QFont::StyleHint(d->request.styleHint), script: QChar::Script_Common);
2701 if (!fallbacks.isEmpty())
2702 return fallbacks.first();
2703 return QString();
2704}
2705
2706/*!
2707 \since 5.13
2708
2709 Returns the requested font family names, i.e. the names set in the last
2710 setFamilies() call or via the constructor. Otherwise it returns an
2711 empty list.
2712
2713 \sa setFamily(), setFamilies(), family(), substitutes(), substitute()
2714*/
2715
2716QStringList QFont::families() const
2717{
2718 return d->request.families;
2719}
2720
2721/*!
2722 \since 5.13
2723
2724 Sets the list of family names for the font. The names are case
2725 insensitive and may include a foundry name. The first family in
2726 \a families will be set as the main family for the font.
2727
2728 Each family name entry in \a families may optionally also include a
2729 foundry name, e.g. "Helvetica [Cronyx]". If the family is
2730 available from more than one foundry and the foundry isn't
2731 specified, an arbitrary foundry is chosen. If the family isn't
2732 available a family will be set using the \l{QFont}{font matching}
2733 algorithm.
2734
2735 \sa family(), families(), setFamily(), setStyleHint(), QFontInfo
2736*/
2737
2738void QFont::setFamilies(const QStringList &families)
2739{
2740 if ((resolve_mask & QFont::FamiliesResolved) && d->request.families == families)
2741 return;
2742 detach();
2743 d->request.families = families;
2744 resolve_mask |= QFont::FamiliesResolved;
2745}
2746
2747
2748/*****************************************************************************
2749 QFont stream functions
2750 *****************************************************************************/
2751#ifndef QT_NO_DATASTREAM
2752
2753/*!
2754 \relates QFont
2755
2756 Writes the font \a font to the data stream \a s. (toString()
2757 writes to a text stream.)
2758
2759 \sa{Serializing Qt Data Types}{Format of the QDataStream operators}
2760*/
2761QDataStream &operator<<(QDataStream &s, const QFont &font)
2762{
2763 if (s.version() == 1) {
2764 s << font.d->request.families.constFirst().toLatin1();
2765 } else {
2766 s << font.d->request.families.constFirst();
2767 if (s.version() >= QDataStream::Qt_5_4)
2768 s << font.d->request.styleName;
2769 }
2770
2771 if (s.version() >= QDataStream::Qt_4_0) {
2772 // 4.0
2773 double pointSize = font.d->request.pointSize;
2774 qint32 pixelSize = font.d->request.pixelSize;
2775 s << pointSize;
2776 s << pixelSize;
2777 } else if (s.version() <= 3) {
2778 qint16 pointSize = (qint16) (font.d->request.pointSize * 10);
2779 if (pointSize < 0) {
2780 pointSize = (qint16)QFontInfo(font).pointSize() * 10;
2781 }
2782 s << pointSize;
2783 } else {
2784 s << (qint16) (font.d->request.pointSize * 10);
2785 s << (qint16) font.d->request.pixelSize;
2786 }
2787
2788 s << (quint8) font.d->request.styleHint;
2789 if (s.version() >= QDataStream::Qt_3_1) {
2790 // Continue writing 8 bits for versions < 5.4 so that we don't write too much,
2791 // even though we need 16 to store styleStrategy, so there is some data loss.
2792 if (s.version() >= QDataStream::Qt_5_4)
2793 s << (quint16) font.d->request.styleStrategy;
2794 else
2795 s << (quint8) font.d->request.styleStrategy;
2796 }
2797
2798 if (s.version() < QDataStream::Qt_6_0)
2799 s << quint8(0) << quint8(qt_openTypeToLegacyWeight(weight: font.d->request.weight));
2800 else
2801 s << quint16(font.d->request.weight);
2802
2803 s << get_font_bits(version: s.version(), f: font.d.data());
2804 if (s.version() >= QDataStream::Qt_4_3)
2805 s << (quint16)font.d->request.stretch;
2806 if (s.version() >= QDataStream::Qt_4_4)
2807 s << get_extended_font_bits(f: font.d.data());
2808 if (s.version() >= QDataStream::Qt_4_5) {
2809 s << font.d->letterSpacing.value();
2810 s << font.d->wordSpacing.value();
2811 }
2812 if (s.version() >= QDataStream::Qt_5_4)
2813 s << (quint8)font.d->request.hintingPreference;
2814 if (s.version() >= QDataStream::Qt_5_6)
2815 s << (quint8)font.d->capital;
2816 if (s.version() >= QDataStream::Qt_5_13) {
2817 if (s.version() < QDataStream::Qt_6_0)
2818 s << font.d->request.families.mid(pos: 1);
2819 else
2820 s << font.d->request.families;
2821 }
2822 if (s.version() >= QDataStream::Qt_6_6)
2823 s << font.d->features;
2824 if (s.version() >= QDataStream::Qt_6_7)
2825 s << font.d->request.variableAxisValues;
2826 return s;
2827}
2828
2829
2830/*!
2831 \relates QFont
2832
2833 Reads the font \a font from the data stream \a s. (fromString()
2834 reads from a text stream.)
2835
2836 \sa{Serializing Qt Data Types}{Format of the QDataStream operators}
2837*/
2838QDataStream &operator>>(QDataStream &s, QFont &font)
2839{
2840 font.d = new QFontPrivate;
2841 font.resolve_mask = QFont::AllPropertiesResolved;
2842
2843 quint8 styleHint, bits;
2844 quint16 styleStrategy = QFont::PreferDefault;
2845
2846 if (s.version() == 1) {
2847 QByteArray fam;
2848 s >> fam;
2849 font.d->request.families = QStringList(QString::fromLatin1(ba: fam));
2850 } else {
2851 QString fam;
2852 s >> fam;
2853 font.d->request.families = QStringList(fam);
2854 if (s.version() >= QDataStream::Qt_5_4)
2855 s >> font.d->request.styleName;
2856 }
2857
2858 if (s.version() >= QDataStream::Qt_4_0) {
2859 // 4.0
2860 double pointSize;
2861 qint32 pixelSize;
2862 s >> pointSize;
2863 s >> pixelSize;
2864 font.d->request.pointSize = qreal(pointSize);
2865 font.d->request.pixelSize = pixelSize;
2866 } else {
2867 qint16 pointSize, pixelSize = -1;
2868 s >> pointSize;
2869 if (s.version() >= 4)
2870 s >> pixelSize;
2871 font.d->request.pointSize = qreal(pointSize / 10.);
2872 font.d->request.pixelSize = pixelSize;
2873 }
2874 s >> styleHint;
2875 if (s.version() >= QDataStream::Qt_3_1) {
2876 if (s.version() >= QDataStream::Qt_5_4) {
2877 s >> styleStrategy;
2878 } else {
2879 quint8 tempStyleStrategy;
2880 s >> tempStyleStrategy;
2881 styleStrategy = tempStyleStrategy;
2882 }
2883 }
2884
2885 if (s.version() < QDataStream::Qt_6_0) {
2886 quint8 charSet;
2887 quint8 weight;
2888 s >> charSet;
2889 s >> weight;
2890 font.d->request.weight = qt_legacyToOpenTypeWeight(weight);
2891 } else {
2892 quint16 weight;
2893 s >> weight;
2894 font.d->request.weight = weight;
2895 }
2896
2897 s >> bits;
2898
2899 font.d->request.styleHint = styleHint;
2900 font.d->request.styleStrategy = styleStrategy;
2901
2902 set_font_bits(version: s.version(), bits, f: font.d.data());
2903
2904 if (s.version() >= QDataStream::Qt_4_3) {
2905 quint16 stretch;
2906 s >> stretch;
2907 font.d->request.stretch = stretch;
2908 }
2909
2910 if (s.version() >= QDataStream::Qt_4_4) {
2911 quint8 extendedBits;
2912 s >> extendedBits;
2913 set_extended_font_bits(bits: extendedBits, f: font.d.data());
2914 }
2915 if (s.version() >= QDataStream::Qt_4_5) {
2916 int value;
2917 s >> value;
2918 font.d->letterSpacing.setValue(value);
2919 s >> value;
2920 font.d->wordSpacing.setValue(value);
2921 }
2922 if (s.version() >= QDataStream::Qt_5_4) {
2923 quint8 value;
2924 s >> value;
2925 font.d->request.hintingPreference = QFont::HintingPreference(value);
2926 }
2927 if (s.version() >= QDataStream::Qt_5_6) {
2928 quint8 value;
2929 s >> value;
2930 font.d->capital = QFont::Capitalization(value);
2931 }
2932 if (s.version() >= QDataStream::Qt_5_13) {
2933 QStringList value;
2934 s >> value;
2935 if (s.version() < QDataStream::Qt_6_0)
2936 font.d->request.families.append(l: value);
2937 else
2938 font.d->request.families = value;
2939 }
2940 if (s.version() >= QDataStream::Qt_6_6) {
2941 font.d->features.clear();
2942 s >> font.d->features;
2943 }
2944 if (s.version() >= QDataStream::Qt_6_7) {
2945 font.d->request.variableAxisValues.clear();
2946 s >> font.d->request.variableAxisValues;
2947 }
2948
2949 return s;
2950}
2951
2952QDataStream &operator<<(QDataStream &stream, QFont::Tag tag)
2953{
2954 stream << tag.value();
2955 return stream;
2956}
2957
2958QDataStream &operator>>(QDataStream &stream, QFont::Tag &tag)
2959{
2960 quint32 value;
2961 stream >> value;
2962 if (const auto maybeTag = QFont::Tag::fromValue(value))
2963 tag = *maybeTag;
2964 else
2965 stream.setStatus(QDataStream::ReadCorruptData);
2966 return stream;
2967}
2968
2969#endif // QT_NO_DATASTREAM
2970
2971
2972/*****************************************************************************
2973 QFontInfo member functions
2974 *****************************************************************************/
2975
2976/*!
2977 \class QFontInfo
2978 \reentrant
2979
2980 \brief The QFontInfo class provides general information about fonts.
2981 \inmodule QtGui
2982
2983 \ingroup appearance
2984 \ingroup shared
2985
2986 The QFontInfo class provides the same access functions as QFont,
2987 e.g. family(), pointSize(), italic(), weight(), fixedPitch(),
2988 styleHint() etc. But whilst the QFont access functions return the
2989 values that were set, a QFontInfo object returns the values that
2990 apply to the font that will actually be used to draw the text.
2991
2992 For example, when the program asks for a 25pt Courier font on a
2993 machine that has a non-scalable 24pt Courier font, QFont will
2994 (normally) use the 24pt Courier for rendering. In this case,
2995 QFont::pointSize() returns 25 and QFontInfo::pointSize() returns
2996 24.
2997
2998 There are three ways to create a QFontInfo object.
2999 \list 1
3000 \li Calling the QFontInfo constructor with a QFont creates a font
3001 info object for a screen-compatible font, i.e. the font cannot be
3002 a printer font. If the font is changed later, the font
3003 info object is \e not updated.
3004
3005 (Note: If you use a printer font the values returned may be
3006 inaccurate. Printer fonts are not always accessible so the nearest
3007 screen font is used if a printer font is supplied.)
3008
3009 \li QWidget::fontInfo() returns the font info for a widget's font.
3010 This is equivalent to calling QFontInfo(widget->font()). If the
3011 widget's font is changed later, the font info object is \e not
3012 updated.
3013
3014 \li QPainter::fontInfo() returns the font info for a painter's
3015 current font. If the painter's font is changed later, the font
3016 info object is \e not updated.
3017 \endlist
3018
3019 \section1 Checking for the existence of a font
3020
3021 Sometimes it can be useful to check if a font exists before attempting
3022 to use it. The most thorough way of doing so is by using \l {exactMatch()}:
3023
3024 \code
3025 const QFont segoeFont(QLatin1String("Segoe UI"));
3026 if (QFontInfo(segoeFont).exactMatch()) {
3027 // Use the font...
3028 }
3029 \endcode
3030
3031 However, this deep search of families can be expensive on some platforms.
3032 \c QFontDatabase::families().contains() is a faster, but less thorough
3033 alternative:
3034
3035 \code
3036 const QLatin1String segoeUiFamilyName("Segoe UI");
3037 if (QFontDatabase::families().contains(segoeUiFamilyName)) {
3038 const QFont segoeFont(segoeUiFamilyName);
3039 // Use the font...
3040 }
3041 \endcode
3042
3043 It's less thorough because it's not a complete search: some font family
3044 aliases may be missing from the list. However, this approach results in
3045 faster application startup times, and so should always be preferred if
3046 possible.
3047
3048 \sa QFont, QFontMetrics, QFontDatabase
3049*/
3050
3051/*!
3052 Constructs a font info object for \a font.
3053
3054 The font must be screen-compatible, i.e. a font you use when
3055 drawing text in \l{QWidget}{widgets} or \l{QPixmap}{pixmaps}, not QPicture or QPrinter.
3056
3057 The font info object holds the information for the font that is
3058 passed in the constructor at the time it is created, and is not
3059 updated if the font's attributes are changed later.
3060
3061 Use QPainter::fontInfo() to get the font info when painting.
3062 This will give correct results also when painting on paint device
3063 that is not screen-compatible.
3064
3065 \sa {Checking for the existence of a font}
3066*/
3067QFontInfo::QFontInfo(const QFont &font)
3068 : d(font.d)
3069{
3070}
3071
3072/*!
3073 Constructs a copy of \a fi.
3074*/
3075QFontInfo::QFontInfo(const QFontInfo &fi)
3076 : d(fi.d)
3077{
3078}
3079
3080/*!
3081 Destroys the font info object.
3082*/
3083QFontInfo::~QFontInfo()
3084{
3085}
3086
3087/*!
3088 Assigns the font info in \a fi.
3089*/
3090QFontInfo &QFontInfo::operator=(const QFontInfo &fi)
3091{
3092 d = fi.d;
3093 return *this;
3094}
3095
3096/*!
3097 \fn void QFontInfo::swap(QFontInfo &other)
3098 \since 5.0
3099
3100 Swaps this font info instance with \a other. This function is very
3101 fast and never fails.
3102*/
3103
3104/*!
3105 Returns the family name of the matched window system font.
3106
3107 \sa QFont::family(), {Checking for the existence of a font}
3108*/
3109QString QFontInfo::family() const
3110{
3111 QFontEngine *engine = d->engineForScript(script: QChar::Script_Common);
3112 Q_ASSERT(engine != nullptr);
3113 return engine->fontDef.families.isEmpty() ? QString() : engine->fontDef.families.constFirst();
3114}
3115
3116/*!
3117 \since 4.8
3118
3119 Returns the style name of the matched window system font on
3120 systems that support it.
3121
3122 \sa QFont::styleName()
3123*/
3124QString QFontInfo::styleName() const
3125{
3126 QFontEngine *engine = d->engineForScript(script: QChar::Script_Common);
3127 Q_ASSERT(engine != nullptr);
3128 return engine->fontDef.styleName;
3129}
3130
3131/*!
3132 Returns the point size of the matched window system font.
3133
3134 \sa pointSizeF(), QFont::pointSize()
3135*/
3136int QFontInfo::pointSize() const
3137{
3138 QFontEngine *engine = d->engineForScript(script: QChar::Script_Common);
3139 Q_ASSERT(engine != nullptr);
3140 return qRound(d: engine->fontDef.pointSize);
3141}
3142
3143/*!
3144 Returns the point size of the matched window system font.
3145
3146 \sa QFont::pointSizeF()
3147*/
3148qreal QFontInfo::pointSizeF() const
3149{
3150 QFontEngine *engine = d->engineForScript(script: QChar::Script_Common);
3151 Q_ASSERT(engine != nullptr);
3152 return engine->fontDef.pointSize;
3153}
3154
3155/*!
3156 Returns the pixel size of the matched window system font.
3157
3158 \sa QFont::pointSize()
3159*/
3160int QFontInfo::pixelSize() const
3161{
3162 QFontEngine *engine = d->engineForScript(script: QChar::Script_Common);
3163 Q_ASSERT(engine != nullptr);
3164 return engine->fontDef.pixelSize;
3165}
3166
3167/*!
3168 Returns the italic value of the matched window system font.
3169
3170 \sa QFont::italic()
3171*/
3172bool QFontInfo::italic() const
3173{
3174 QFontEngine *engine = d->engineForScript(script: QChar::Script_Common);
3175 Q_ASSERT(engine != nullptr);
3176 return engine->fontDef.style != QFont::StyleNormal;
3177}
3178
3179/*!
3180 Returns the style value of the matched window system font.
3181
3182 \sa QFont::style()
3183*/
3184QFont::Style QFontInfo::style() const
3185{
3186 QFontEngine *engine = d->engineForScript(script: QChar::Script_Common);
3187 Q_ASSERT(engine != nullptr);
3188 return (QFont::Style)engine->fontDef.style;
3189}
3190
3191
3192#if QT_DEPRECATED_SINCE(6, 0)
3193/*!
3194 \deprecated Use weight() instead.
3195
3196 Returns the weight of the font converted to the non-standard font
3197 weight scale used in Qt 5 and earlier versions.
3198
3199 Since Qt 6, the OpenType standard's font weight scale is used instead
3200 of a non-standard scale. This requires conversion from values that
3201 use the old scale. For convenience, this function may be used when
3202 porting from code which uses the old weight scale.
3203
3204 \sa QFont::setWeight(), weight(), QFontInfo
3205*/
3206int QFontInfo::legacyWeight() const
3207{
3208 return qt_openTypeToLegacyWeight(weight: weight());
3209}
3210#endif // QT_DEPRECATED_SINCE(6, 0)
3211
3212
3213/*!
3214 Returns the weight of the matched window system font.
3215
3216 \sa QFont::weight(), bold()
3217*/
3218int QFontInfo::weight() const
3219{
3220 QFontEngine *engine = d->engineForScript(script: QChar::Script_Common);
3221 Q_ASSERT(engine != nullptr);
3222 return engine->fontDef.weight;
3223
3224}
3225
3226/*!
3227 \fn bool QFontInfo::bold() const
3228
3229 Returns \c true if weight() would return a value greater than
3230 QFont::Normal; otherwise returns \c false.
3231
3232 \sa weight(), QFont::bold()
3233*/
3234
3235/*!
3236 Returns the underline value of the matched window system font.
3237
3238 \sa QFont::underline()
3239
3240 \internal
3241
3242 Here we read the underline flag directly from the QFont.
3243 This is OK for X11 and for Windows because we always get what we want.
3244*/
3245bool QFontInfo::underline() const
3246{
3247 return d->underline;
3248}
3249
3250/*!
3251 Returns the overline value of the matched window system font.
3252
3253 \sa QFont::overline()
3254
3255 \internal
3256
3257 Here we read the overline flag directly from the QFont.
3258 This is OK for X11 and for Windows because we always get what we want.
3259*/
3260bool QFontInfo::overline() const
3261{
3262 return d->overline;
3263}
3264
3265/*!
3266 Returns the strikeout value of the matched window system font.
3267
3268 \sa QFont::strikeOut()
3269
3270 \internal Here we read the strikeOut flag directly from the QFont.
3271 This is OK for X11 and for Windows because we always get what we want.
3272*/
3273bool QFontInfo::strikeOut() const
3274{
3275 return d->strikeOut;
3276}
3277
3278/*!
3279 Returns the fixed pitch value of the matched window system font.
3280
3281 \sa QFont::fixedPitch()
3282*/
3283bool QFontInfo::fixedPitch() const
3284{
3285 QFontEngine *engine = d->engineForScript(script: QChar::Script_Common);
3286 Q_ASSERT(engine != nullptr);
3287#ifdef Q_OS_MAC
3288 if (!engine->fontDef.fixedPitchComputed) {
3289 QChar ch[2] = { u'i', u'm' };
3290 QGlyphLayoutArray<2> g;
3291 int l = 2;
3292 if (engine->stringToCMap(ch, 2, &g, &l, {}) < 0)
3293 Q_UNREACHABLE();
3294 Q_ASSERT(l == 2);
3295 engine->fontDef.fixedPitch = g.advances[0] == g.advances[1];
3296 engine->fontDef.fixedPitchComputed = true;
3297 }
3298#endif
3299 return engine->fontDef.fixedPitch;
3300}
3301
3302/*!
3303 Returns the style of the matched window system font.
3304
3305 Currently only returns the style hint set in QFont.
3306
3307 \sa QFont::styleHint(), QFont::StyleHint
3308*/
3309QFont::StyleHint QFontInfo::styleHint() const
3310{
3311 QFontEngine *engine = d->engineForScript(script: QChar::Script_Common);
3312 Q_ASSERT(engine != nullptr);
3313 return (QFont::StyleHint) engine->fontDef.styleHint;
3314}
3315
3316/*!
3317 Returns \c true if the matched window system font is exactly the same
3318 as the one specified by the font; otherwise returns \c false.
3319
3320 \sa QFont::exactMatch()
3321*/
3322bool QFontInfo::exactMatch() const
3323{
3324 QFontEngine *engine = d->engineForScript(script: QChar::Script_Common);
3325 Q_ASSERT(engine != nullptr);
3326 return d->request.exactMatch(other: engine->fontDef);
3327}
3328
3329
3330
3331
3332// **********************************************************************
3333// QFontCache
3334// **********************************************************************
3335
3336using namespace std::chrono_literals;
3337
3338#ifdef QFONTCACHE_DEBUG
3339// fast timeouts for debugging
3340static constexpr auto fast_timeout = 1s;
3341static constexpr auto slow_timeout = 5s;
3342#else
3343static constexpr auto fast_timeout = 10s;
3344static constexpr auto slow_timeout = 5min;
3345#endif // QFONTCACHE_DEBUG
3346
3347#ifndef QFONTCACHE_MIN_COST
3348# define QFONTCACHE_MIN_COST 4*1024 // 4mb
3349#endif
3350const uint QFontCache::min_cost = QFONTCACHE_MIN_COST;
3351Q_GLOBAL_STATIC(QThreadStorage<QFontCache *>, theFontCache)
3352
3353QFontCache *QFontCache::instance()
3354{
3355 QFontCache *&fontCache = theFontCache()->localData();
3356 if (!fontCache)
3357 fontCache = new QFontCache;
3358 return fontCache;
3359}
3360
3361void QFontCache::cleanup()
3362{
3363 QThreadStorage<QFontCache *> *cache = nullptr;
3364 QT_TRY {
3365 cache = theFontCache();
3366 } QT_CATCH (const std::bad_alloc &) {
3367 // no cache - just ignore
3368 }
3369 if (cache && cache->hasLocalData())
3370 cache->setLocalData(nullptr);
3371}
3372
3373Q_CONSTINIT static QBasicAtomicInt font_cache_id = Q_BASIC_ATOMIC_INITIALIZER(0);
3374
3375QFontCache::QFontCache()
3376 : QObject(), total_cost(0), max_cost(min_cost),
3377 current_timestamp(0), fast(false),
3378 autoClean(QGuiApplication::instance()
3379 && (QGuiApplication::instance()->thread() == QThread::currentThread())),
3380 timer_id(-1),
3381 m_id(font_cache_id.fetchAndAddRelaxed(valueToAdd: 1) + 1)
3382{
3383}
3384
3385QFontCache::~QFontCache()
3386{
3387 clear();
3388}
3389
3390void QFontCache::clear()
3391{
3392 {
3393 EngineDataCache::Iterator it = engineDataCache.begin(),
3394 end = engineDataCache.end();
3395 while (it != end) {
3396 QFontEngineData *data = it.value();
3397 for (int i = 0; i < QChar::ScriptCount; ++i) {
3398 if (data->engines[i]) {
3399 if (!data->engines[i]->ref.deref()) {
3400 Q_ASSERT(engineCacheCount.value(data->engines[i]) == 0);
3401 delete data->engines[i];
3402 }
3403 data->engines[i] = nullptr;
3404 }
3405 }
3406 if (!data->ref.deref()) {
3407 delete data;
3408 } else {
3409 FC_DEBUG(msg: "QFontCache::clear: engineData %p still has refcount %d",
3410 data, data->ref.loadRelaxed());
3411 }
3412 ++it;
3413 }
3414 }
3415
3416 engineDataCache.clear();
3417
3418
3419 bool mightHaveEnginesLeftForCleanup;
3420 do {
3421 mightHaveEnginesLeftForCleanup = false;
3422 for (EngineCache::Iterator it = engineCache.begin(), end = engineCache.end();
3423 it != end; ++it) {
3424 QFontEngine *engine = it.value().data;
3425 if (engine) {
3426 const int cacheCount = --engineCacheCount[engine];
3427 Q_ASSERT(cacheCount >= 0);
3428 if (!engine->ref.deref()) {
3429 Q_ASSERT(cacheCount == 0);
3430 mightHaveEnginesLeftForCleanup = engine->type() == QFontEngine::Multi;
3431 delete engine;
3432 } else if (cacheCount == 0) {
3433 FC_DEBUG(msg: "QFontCache::clear: engine %p still has refcount %d",
3434 engine, engine->ref.loadRelaxed());
3435 }
3436 it.value().data = nullptr;
3437 }
3438 }
3439 } while (mightHaveEnginesLeftForCleanup);
3440
3441 engineCache.clear();
3442 engineCacheCount.clear();
3443
3444
3445 total_cost = 0;
3446 max_cost = min_cost;
3447}
3448
3449
3450QFontEngineData *QFontCache::findEngineData(const QFontDef &def) const
3451{
3452 EngineDataCache::ConstIterator it = engineDataCache.constFind(key: def);
3453 if (it == engineDataCache.constEnd())
3454 return nullptr;
3455
3456 // found
3457 return it.value();
3458}
3459
3460void QFontCache::insertEngineData(const QFontDef &def, QFontEngineData *engineData)
3461{
3462#ifdef QFONTCACHE_DEBUG
3463 FC_DEBUG("QFontCache: inserting new engine data %p", engineData);
3464 if (engineDataCache.contains(def)) {
3465 FC_DEBUG(" QFontCache already contains engine data %p for key=(%g %g %d %d %d)",
3466 engineDataCache.value(def), def.pointSize,
3467 def.pixelSize, def.weight, def.style, def.fixedPitch);
3468 }
3469#endif
3470 Q_ASSERT(!engineDataCache.contains(def));
3471
3472 engineData->ref.ref();
3473 // Decrease now rather than waiting
3474 if (total_cost > min_cost * 2 && engineDataCache.size() >= QFONTCACHE_DECREASE_TRIGGER_LIMIT)
3475 decreaseCache();
3476
3477 engineDataCache.insert(key: def, value: engineData);
3478 increaseCost(cost: sizeof(QFontEngineData));
3479}
3480
3481QFontEngine *QFontCache::findEngine(const Key &key)
3482{
3483 EngineCache::Iterator it = engineCache.find(key),
3484 end = engineCache.end();
3485 if (it == end) return nullptr;
3486
3487 Q_ASSERT(it.value().data != nullptr);
3488 Q_ASSERT(key.multi == (it.value().data->type() == QFontEngine::Multi));
3489
3490 // found... update the hitcount and timestamp
3491 updateHitCountAndTimeStamp(value&: it.value());
3492
3493 return it.value().data;
3494}
3495
3496void QFontCache::updateHitCountAndTimeStamp(Engine &value)
3497{
3498 value.hits++;
3499 value.timestamp = ++current_timestamp;
3500
3501 FC_DEBUG(msg: "QFontCache: found font engine\n"
3502 " %p: timestamp %4u hits %3u ref %2d/%2d, type %d",
3503 value.data, value.timestamp, value.hits,
3504 value.data->ref.loadRelaxed(), engineCacheCount.value(key: value.data),
3505 value.data->type());
3506}
3507
3508void QFontCache::insertEngine(const Key &key, QFontEngine *engine, bool insertMulti)
3509{
3510 Q_ASSERT(engine != nullptr);
3511 Q_ASSERT(key.multi == (engine->type() == QFontEngine::Multi));
3512
3513#ifdef QFONTCACHE_DEBUG
3514 FC_DEBUG("QFontCache: inserting new engine %p, refcount %d", engine, engine->ref.loadRelaxed());
3515 if (!insertMulti && engineCache.contains(key)) {
3516 FC_DEBUG(" QFontCache already contains engine %p for key=(%g %g %d %d %d)",
3517 engineCache.value(key).data, key.def.pointSize,
3518 key.def.pixelSize, key.def.weight, key.def.style, key.def.fixedPitch);
3519 }
3520#endif
3521 engine->ref.ref();
3522 // Decrease now rather than waiting
3523 if (total_cost > min_cost * 2 && engineCache.size() >= QFONTCACHE_DECREASE_TRIGGER_LIMIT)
3524 decreaseCache();
3525
3526 Engine data(engine);
3527 data.timestamp = ++current_timestamp;
3528
3529 if (insertMulti)
3530 engineCache.insert(key, value: data);
3531 else
3532 engineCache.replace(key, value: data);
3533 // only increase the cost if this is the first time we insert the engine
3534 if (++engineCacheCount[engine] == 1)
3535 increaseCost(cost: engine->cache_cost);
3536}
3537
3538void QFontCache::increaseCost(uint cost)
3539{
3540 cost = (cost + 512) / 1024; // store cost in kb
3541 cost = cost > 0 ? cost : 1;
3542 total_cost += cost;
3543
3544 FC_DEBUG(msg: " COST: increased %u kb, total_cost %u kb, max_cost %u kb",
3545 cost, total_cost, max_cost);
3546
3547 if (total_cost > max_cost) {
3548 max_cost = total_cost;
3549
3550 if (!autoClean)
3551 return;
3552
3553 if (timer_id == -1 || ! fast) {
3554 FC_DEBUG(msg: " TIMER: starting fast timer (%d s)", static_cast<int>(fast_timeout.count()));
3555
3556 if (timer_id != -1)
3557 killTimer(id: timer_id);
3558 timer_id = startTimer(time: fast_timeout);
3559 fast = true;
3560 }
3561 }
3562}
3563
3564void QFontCache::decreaseCost(uint cost)
3565{
3566 cost = (cost + 512) / 1024; // cost is stored in kb
3567 cost = cost > 0 ? cost : 1;
3568 Q_ASSERT(cost <= total_cost);
3569 total_cost -= cost;
3570
3571 FC_DEBUG(msg: " COST: decreased %u kb, total_cost %u kb, max_cost %u kb",
3572 cost, total_cost, max_cost);
3573}
3574
3575void QFontCache::timerEvent(QTimerEvent *)
3576{
3577 FC_DEBUG(msg: "QFontCache::timerEvent: performing cache maintenance (timestamp %u)",
3578 current_timestamp);
3579
3580 if (total_cost <= max_cost && max_cost <= min_cost) {
3581 FC_DEBUG(msg: " cache redused sufficiently, stopping timer");
3582
3583 killTimer(id: timer_id);
3584 timer_id = -1;
3585 fast = false;
3586
3587 return;
3588 }
3589 decreaseCache();
3590}
3591
3592void QFontCache::decreaseCache()
3593{
3594 // go through the cache and count up everything in use
3595 uint in_use_cost = 0;
3596
3597 {
3598 FC_DEBUG(msg: " SWEEP engine data:");
3599
3600 // make sure the cost of each engine data is at least 1kb
3601 const uint engine_data_cost =
3602 sizeof(QFontEngineData) > 1024 ? sizeof(QFontEngineData) : 1024;
3603
3604 EngineDataCache::ConstIterator it = engineDataCache.constBegin(),
3605 end = engineDataCache.constEnd();
3606 for (; it != end; ++it) {
3607 FC_DEBUG(msg: " %p: ref %2d", it.value(), int(it.value()->ref.loadRelaxed()));
3608
3609 if (it.value()->ref.loadRelaxed() != 1)
3610 in_use_cost += engine_data_cost;
3611 }
3612 }
3613
3614 {
3615 FC_DEBUG(msg: " SWEEP engine:");
3616
3617 EngineCache::ConstIterator it = engineCache.constBegin(),
3618 end = engineCache.constEnd();
3619 for (; it != end; ++it) {
3620 FC_DEBUG(msg: " %p: timestamp %4u hits %2u ref %2d/%2d, cost %u bytes",
3621 it.value().data, it.value().timestamp, it.value().hits,
3622 it.value().data->ref.loadRelaxed(), engineCacheCount.value(key: it.value().data),
3623 it.value().data->cache_cost);
3624
3625 if (it.value().data->ref.loadRelaxed() > engineCacheCount.value(key: it.value().data))
3626 in_use_cost += it.value().data->cache_cost / engineCacheCount.value(key: it.value().data);
3627 }
3628
3629 // attempt to make up for rounding errors
3630 in_use_cost += engineCache.size();
3631 }
3632
3633 in_use_cost = (in_use_cost + 512) / 1024; // cost is stored in kb
3634
3635 /*
3636 calculate the new maximum cost for the cache
3637
3638 NOTE: in_use_cost is *not* correct due to rounding errors in the
3639 above algorithm. instead of worrying about getting the
3640 calculation correct, we are more interested in speed, and use
3641 in_use_cost as a floor for new_max_cost
3642 */
3643 uint new_max_cost = qMax(a: qMax(a: max_cost / 2, b: in_use_cost), b: min_cost);
3644
3645 FC_DEBUG(msg: " after sweep, in use %u kb, total %u kb, max %u kb, new max %u kb",
3646 in_use_cost, total_cost, max_cost, new_max_cost);
3647
3648 if (autoClean) {
3649 if (new_max_cost == max_cost) {
3650 if (fast) {
3651 FC_DEBUG(msg: " cannot shrink cache, slowing timer");
3652
3653 if (timer_id != -1) {
3654 killTimer(id: timer_id);
3655 timer_id = startTimer(time: slow_timeout);
3656 fast = false;
3657 }
3658
3659 return;
3660 } else if (! fast) {
3661 FC_DEBUG(msg: " dropping into passing gear");
3662
3663 if (timer_id != -1)
3664 killTimer(id: timer_id);
3665 timer_id = startTimer(time: fast_timeout);
3666 fast = true; }
3667 }
3668 }
3669
3670 max_cost = new_max_cost;
3671
3672 {
3673 FC_DEBUG(msg: " CLEAN engine data:");
3674
3675 // clean out all unused engine data
3676 EngineDataCache::Iterator it = engineDataCache.begin();
3677 while (it != engineDataCache.end()) {
3678 if (it.value()->ref.loadRelaxed() == 1) {
3679 FC_DEBUG(msg: " %p", it.value());
3680 decreaseCost(cost: sizeof(QFontEngineData));
3681 it.value()->ref.deref();
3682 delete it.value();
3683 it = engineDataCache.erase(it);
3684 } else {
3685 ++it;
3686 }
3687 }
3688 }
3689
3690 FC_DEBUG(msg: " CLEAN engine:");
3691
3692 // clean out the engine cache just enough to get below our new max cost
3693 bool cost_decreased;
3694 do {
3695 cost_decreased = false;
3696
3697 EngineCache::Iterator it = engineCache.begin(),
3698 end = engineCache.end();
3699 // determine the oldest and least popular of the unused engines
3700 uint oldest = ~0u;
3701 uint least_popular = ~0u;
3702
3703 EngineCache::Iterator jt = end;
3704
3705 for ( ; it != end; ++it) {
3706 if (it.value().data->ref.loadRelaxed() != engineCacheCount.value(key: it.value().data))
3707 continue;
3708
3709 if (it.value().timestamp < oldest && it.value().hits <= least_popular) {
3710 oldest = it.value().timestamp;
3711 least_popular = it.value().hits;
3712 jt = it;
3713 }
3714 }
3715
3716 it = jt;
3717 if (it != end) {
3718 FC_DEBUG(msg: " %p: timestamp %4u hits %2u ref %2d/%2d, type %d",
3719 it.value().data, it.value().timestamp, it.value().hits,
3720 it.value().data->ref.loadRelaxed(), engineCacheCount.value(key: it.value().data),
3721 it.value().data->type());
3722
3723 QFontEngine *fontEngine = it.value().data;
3724 // get rid of all occurrences
3725 it = engineCache.begin();
3726 while (it != engineCache.end()) {
3727 if (it.value().data == fontEngine) {
3728 fontEngine->ref.deref();
3729 it = engineCache.erase(it);
3730 } else {
3731 ++it;
3732 }
3733 }
3734 // and delete the last occurrence
3735 Q_ASSERT(fontEngine->ref.loadRelaxed() == 0);
3736 decreaseCost(cost: fontEngine->cache_cost);
3737 delete fontEngine;
3738 engineCacheCount.remove(key: fontEngine);
3739
3740 cost_decreased = true;
3741 }
3742 } while (cost_decreased && total_cost > max_cost);
3743}
3744
3745
3746#ifndef QT_NO_DEBUG_STREAM
3747QDebug operator<<(QDebug stream, const QFont &font)
3748{
3749 QDebugStateSaver saver(stream);
3750 stream.nospace().noquote();
3751 stream << "QFont(";
3752
3753 if (stream.verbosity() == QDebug::DefaultVerbosity) {
3754 stream << font.toString() << ")";
3755 return stream;
3756 }
3757
3758 QString fontDescription;
3759 QDebug debug(&fontDescription);
3760 debug.nospace();
3761
3762 const QFont defaultFont(new QFontPrivate);
3763
3764 for (int property = QFont::SizeResolved; property < QFont::AllPropertiesResolved; property <<= 1) {
3765 const bool resolved = (font.resolve_mask & property) != 0;
3766 if (!resolved && stream.verbosity() == QDebug::MinimumVerbosity)
3767 continue;
3768
3769 #define QFONT_DEBUG_SKIP_DEFAULT(prop) \
3770 if ((font.prop() == defaultFont.prop()) && stream.verbosity() == 1) \
3771 continue;
3772
3773 QDebugStateSaver saver(debug);
3774
3775 switch (property) {
3776 case QFont::SizeResolved:
3777 if (font.pointSizeF() >= 0)
3778 debug << font.pointSizeF() << "pt";
3779 else if (font.pixelSize() >= 0)
3780 debug << font.pixelSize() << "px";
3781 else
3782 Q_UNREACHABLE();
3783 break;
3784 case QFont::StyleHintResolved:
3785 QFONT_DEBUG_SKIP_DEFAULT(styleHint);
3786 debug.verbosity(verbosityLevel: 1) << font.styleHint(); break;
3787 case QFont::StyleStrategyResolved:
3788 QFONT_DEBUG_SKIP_DEFAULT(styleStrategy);
3789 debug.verbosity(verbosityLevel: 1) << font.styleStrategy(); break;
3790 case QFont::WeightResolved:
3791 debug.verbosity(verbosityLevel: 1) << QFont::Weight(font.weight()); break;
3792 case QFont::StyleResolved:
3793 QFONT_DEBUG_SKIP_DEFAULT(style);
3794 debug.verbosity(verbosityLevel: 0) << font.style(); break;
3795 case QFont::UnderlineResolved:
3796 QFONT_DEBUG_SKIP_DEFAULT(underline);
3797 debug << "underline=" << font.underline(); break;
3798 case QFont::OverlineResolved:
3799 QFONT_DEBUG_SKIP_DEFAULT(overline);
3800 debug << "overline=" << font.overline(); break;
3801 case QFont::StrikeOutResolved:
3802 QFONT_DEBUG_SKIP_DEFAULT(strikeOut);
3803 debug << "strikeOut=" << font.strikeOut(); break;
3804 case QFont::FixedPitchResolved:
3805 QFONT_DEBUG_SKIP_DEFAULT(fixedPitch);
3806 debug << "fixedPitch=" << font.fixedPitch(); break;
3807 case QFont::StretchResolved:
3808 QFONT_DEBUG_SKIP_DEFAULT(stretch);
3809 debug.verbosity(verbosityLevel: 0) << QFont::Stretch(font.stretch()); break;
3810 case QFont::KerningResolved:
3811 QFONT_DEBUG_SKIP_DEFAULT(kerning);
3812 debug << "kerning=" << font.kerning(); break;
3813 case QFont::CapitalizationResolved:
3814 QFONT_DEBUG_SKIP_DEFAULT(capitalization);
3815 debug.verbosity(verbosityLevel: 0) << font.capitalization(); break;
3816 case QFont::LetterSpacingResolved:
3817 QFONT_DEBUG_SKIP_DEFAULT(letterSpacing);
3818 debug << "letterSpacing=" << font.letterSpacing();
3819 debug.verbosity(verbosityLevel: 0) << " (" << font.letterSpacingType() << ")";
3820 break;
3821 case QFont::HintingPreferenceResolved:
3822 QFONT_DEBUG_SKIP_DEFAULT(hintingPreference);
3823 debug.verbosity(verbosityLevel: 0) << font.hintingPreference(); break;
3824 case QFont::StyleNameResolved:
3825 QFONT_DEBUG_SKIP_DEFAULT(styleName);
3826 debug << "styleName=" << font.styleName(); break;
3827 default:
3828 continue;
3829 };
3830
3831 #undef QFONT_DEBUG_SKIP_DEFAULT
3832
3833 debug << ", ";
3834 }
3835
3836 if (stream.verbosity() > QDebug::MinimumVerbosity)
3837 debug.verbosity(verbosityLevel: 0) << "resolveMask=" << QFlags<QFont::ResolveProperties>(font.resolve_mask);
3838 else
3839 fontDescription.chop(n: 2); // Last ', '
3840
3841 stream << fontDescription << ')';
3842
3843 return stream;
3844}
3845
3846QDebug operator<<(QDebug debug, QFont::Tag tag)
3847{
3848 QDebugStateSaver saver(debug);
3849 debug.noquote() << tag.toString();
3850 return debug;
3851}
3852#endif
3853
3854QT_END_NAMESPACE
3855
3856#include "moc_qfont.cpp"
3857

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

source code of qtbase/src/gui/text/qfont.cpp