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