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

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