Coverage Report

Created: 2026-09-14 07:15

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