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