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