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

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