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