Coverage Report

Created: 2026-02-26 07:48

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