1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the test suite of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
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 General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29
30#include <QtTest/QtTest>
31
32
33#include <qfont.h>
34#include <private/qfont_p.h>
35#include <qfontdatabase.h>
36#include <qfontinfo.h>
37#include <qstringlist.h>
38#include <qguiapplication.h>
39#ifndef QT_NO_WIDGETS
40#include <qwidget.h>
41#endif
42#include <qlist.h>
43
44class tst_QFont : public QObject
45{
46Q_OBJECT
47
48private slots:
49 void getSetCheck();
50 void exactMatch();
51 void compare();
52 void resolve();
53#ifndef QT_NO_WIDGETS
54 void resetFont();
55#endif
56 void isCopyOf();
57 void italicOblique();
58 void insertAndRemoveSubstitutions();
59 void serialize_data();
60 void serialize();
61#if QT_DEPRECATED_SINCE(5, 13)
62 void lastResortFont();
63#endif
64 void styleName();
65 void defaultFamily_data();
66 void defaultFamily();
67 void toAndFromString();
68 void fromStringWithoutStyleName();
69 void fromDegenerateString_data();
70 void fromDegenerateString();
71
72 void sharing();
73 void familyNameWithCommaQuote_data();
74 void familyNameWithCommaQuote();
75 void setFamilies_data();
76 void setFamilies();
77 void setFamiliesAndFamily_data();
78 void setFamiliesAndFamily();
79};
80
81// Testing get/set functions
82void tst_QFont::getSetCheck()
83{
84 QFont obj1;
85 // Style QFont::style()
86 // void QFont::setStyle(Style)
87 obj1.setStyle(QFont::Style(QFont::StyleNormal));
88 QCOMPARE(QFont::Style(QFont::StyleNormal), obj1.style());
89 obj1.setStyle(QFont::Style(QFont::StyleItalic));
90 QCOMPARE(QFont::Style(QFont::StyleItalic), obj1.style());
91 obj1.setStyle(QFont::Style(QFont::StyleOblique));
92 QCOMPARE(QFont::Style(QFont::StyleOblique), obj1.style());
93
94 // StyleStrategy QFont::styleStrategy()
95 // void QFont::setStyleStrategy(StyleStrategy)
96 obj1.setStyleStrategy(QFont::StyleStrategy(QFont::PreferDefault));
97 QCOMPARE(QFont::StyleStrategy(QFont::PreferDefault), obj1.styleStrategy());
98 obj1.setStyleStrategy(QFont::StyleStrategy(QFont::PreferBitmap));
99 QCOMPARE(QFont::StyleStrategy(QFont::PreferBitmap), obj1.styleStrategy());
100 obj1.setStyleStrategy(QFont::StyleStrategy(QFont::PreferDevice));
101 QCOMPARE(QFont::StyleStrategy(QFont::PreferDevice), obj1.styleStrategy());
102 obj1.setStyleStrategy(QFont::StyleStrategy(QFont::PreferOutline));
103 QCOMPARE(QFont::StyleStrategy(QFont::PreferOutline), obj1.styleStrategy());
104 obj1.setStyleStrategy(QFont::StyleStrategy(QFont::ForceOutline));
105 QCOMPARE(QFont::StyleStrategy(QFont::ForceOutline), obj1.styleStrategy());
106 obj1.setStyleStrategy(QFont::StyleStrategy(QFont::PreferMatch));
107 QCOMPARE(QFont::StyleStrategy(QFont::PreferMatch), obj1.styleStrategy());
108 obj1.setStyleStrategy(QFont::StyleStrategy(QFont::PreferQuality));
109 QCOMPARE(QFont::StyleStrategy(QFont::PreferQuality), obj1.styleStrategy());
110 obj1.setStyleStrategy(QFont::StyleStrategy(QFont::PreferAntialias));
111 QCOMPARE(QFont::StyleStrategy(QFont::PreferAntialias), obj1.styleStrategy());
112 obj1.setStyleStrategy(QFont::StyleStrategy(QFont::NoAntialias));
113 QCOMPARE(QFont::StyleStrategy(QFont::NoAntialias), obj1.styleStrategy());
114 obj1.setStyleStrategy(QFont::StyleStrategy(QFont::OpenGLCompatible));
115 QCOMPARE(QFont::StyleStrategy(QFont::OpenGLCompatible), obj1.styleStrategy());
116}
117
118void tst_QFont::exactMatch()
119{
120 QFont font;
121
122 // Check if a non-existing font hasn't an exact match
123 font = QFont( "BogusFont", 33 );
124 QVERIFY( !font.exactMatch() );
125 QVERIFY(!QFont("sans").exactMatch());
126 QVERIFY(!QFont("sans-serif").exactMatch());
127 QVERIFY(!QFont("serif").exactMatch());
128 QVERIFY(!QFont("monospace").exactMatch());
129
130 font.setFamilies(QStringList() << "BogusFont");
131 QVERIFY(!font.exactMatch());
132 QVERIFY(!QFont("sans").exactMatch());
133 QVERIFY(!QFont("sans-serif").exactMatch());
134 QVERIFY(!QFont("serif").exactMatch());
135 QVERIFY(!QFont("monospace").exactMatch());
136
137 // Confirm that exactMatch is true for a valid font
138 QFontDatabase db;
139 const QString family = db.families().first();
140 const QString style = db.styles(family).first();
141 const int pointSize = db.pointSizes(family, style).first();
142 font = db.font(family, style, pointSize);
143 QVERIFY(font.exactMatch());
144
145 if (db.families().contains(str: "Arial")) {
146 font = QFont("Arial");
147 QVERIFY(font.exactMatch());
148 font = QFont(QString());
149 font.setFamilies({"Arial"});
150 QVERIFY(font.exactMatch());
151 }
152}
153
154void tst_QFont::italicOblique()
155{
156 QFontDatabase fdb;
157
158 QStringList families = fdb.families();
159 if (families.isEmpty())
160 return;
161
162 QStringList::ConstIterator f_it, f_end = families.end();
163 for (f_it = families.begin(); f_it != f_end; ++f_it) {
164
165 QString family = *f_it;
166 QStringList styles = fdb.styles(family);
167 QStringList::ConstIterator s_it, s_end = styles.end();
168 for (s_it = styles.begin(); s_it != s_end; ++s_it) {
169 QString style = *s_it;
170
171 if (fdb.isSmoothlyScalable(family, style)) {
172 if (style.contains(s: "Oblique")) {
173 style.replace(before: "Oblique", after: "Italic");
174 } else if (style.contains(s: "Italic")) {
175 style.replace(before: "Italic", after: "Oblique");
176 } else {
177 continue;
178 }
179 QFont f = fdb.font(family, style, pointSize: 12);
180 QVERIFY(f.italic());
181 }
182 }
183 }
184}
185
186void tst_QFont::compare()
187{
188 QFont font;
189 {
190 QFont font2 = font;
191 font2.setPointSize(24);
192 QVERIFY(font != font2);
193 QCOMPARE(font < font2,!(font2 < font));
194 }
195 {
196 QFont font2 = font;
197 font2.setPixelSize(24);
198 QVERIFY(font != font2);
199 QCOMPARE(font < font2,!(font2 < font));
200 }
201
202 font.setPointSize(12);
203 font.setItalic(false);
204 font.setWeight(QFont::Normal);
205 font.setUnderline(false);
206 font.setStrikeOut(false);
207 font.setOverline(false);
208 {
209 QFont font2 = font;
210 font2.setPointSize(24);
211 QVERIFY(font != font2);
212 QCOMPARE(font < font2,!(font2 < font));
213 }
214 {
215 QFont font2 = font;
216 font2.setPixelSize(24);
217 QVERIFY(font != font2);
218 QCOMPARE(font < font2,!(font2 < font));
219 }
220 {
221 QFont font2 = font;
222
223 font2.setItalic(true);
224 QVERIFY(font != font2);
225 QCOMPARE(font < font2,!(font2 < font));
226 font2.setItalic(false);
227 QCOMPARE(font, font2);
228 QVERIFY(!(font < font2));
229
230 font2.setWeight(QFont::Bold);
231 QVERIFY(font != font2);
232 QCOMPARE(font < font2,!(font2 < font));
233 font2.setWeight(QFont::Normal);
234 QCOMPARE(font, font2);
235 QVERIFY(!(font < font2));
236
237 font.setUnderline(true);
238 QVERIFY(font != font2);
239 QCOMPARE(font < font2,!(font2 < font));
240 font.setUnderline(false);
241 QCOMPARE(font, font2);
242 QVERIFY(!(font < font2));
243
244 font.setStrikeOut(true);
245 QVERIFY(font != font2);
246 QCOMPARE(font < font2,!(font2 < font));
247 font.setStrikeOut(false);
248 QCOMPARE(font, font2);
249 QVERIFY(!(font < font2));
250
251 font.setOverline(true);
252 QVERIFY(font != font2);
253 QCOMPARE(font < font2,!(font2 < font));
254 font.setOverline(false);
255 QCOMPARE(font, font2);
256 QVERIFY(!(font < font2));
257
258 font.setCapitalization(QFont::SmallCaps);
259 QVERIFY(font != font2);
260 QCOMPARE(font < font2,!(font2 < font));
261 font.setCapitalization(QFont::MixedCase);
262 QCOMPARE(font, font2);
263 QVERIFY(!(font < font2));
264 }
265}
266
267void tst_QFont::resolve()
268{
269 QFont font;
270 font.setPointSize(font.pointSize() * 2);
271 font.setItalic(false);
272 font.setWeight(QFont::Normal);
273 font.setUnderline(false);
274 font.setStrikeOut(false);
275 font.setOverline(false);
276 font.setStretch(QFont::Unstretched);
277
278 QFont font1;
279 font1.setWeight(QFont::Bold);
280 QFont font2 = font1.resolve(font);
281
282 QCOMPARE(font2.weight(), font1.weight());
283
284 QCOMPARE(font2.pointSize(), font.pointSize());
285 QCOMPARE(font2.italic(), font.italic());
286 QCOMPARE(font2.underline(), font.underline());
287 QCOMPARE(font2.overline(), font.overline());
288 QCOMPARE(font2.strikeOut(), font.strikeOut());
289 QCOMPARE(font2.stretch(), font.stretch());
290
291 QFont font3;
292 font3.setStretch(QFont::UltraCondensed);
293 QFont font4 = font3.resolve(font1).resolve(font);
294
295 QCOMPARE(font4.stretch(), font3.stretch());
296
297 QCOMPARE(font4.weight(), font.weight());
298 QCOMPARE(font4.pointSize(), font.pointSize());
299 QCOMPARE(font4.italic(), font.italic());
300 QCOMPARE(font4.underline(), font.underline());
301 QCOMPARE(font4.overline(), font.overline());
302 QCOMPARE(font4.strikeOut(), font.strikeOut());
303
304
305 QFont f1,f2,f3;
306 f2.setPointSize(45);
307 f3.setPointSize(55);
308
309 QFont f4 = f1.resolve(f2);
310 QCOMPARE(f4.pointSize(), 45);
311 f4 = f4.resolve(f3);
312 QCOMPARE(f4.pointSize(), 55);
313
314 QFont font5, font6;
315 const QStringList fontFamilies = { QStringLiteral("Arial") };
316 font5.setFamilies(fontFamilies);
317 font6 = font6.resolve(font5);
318 QCOMPARE(font6.families(), fontFamilies);
319
320 QFont font7, font8;
321 font7.setFamily(QLatin1String("Helvetica"));
322 font8.setFamilies(fontFamilies);
323 font7 = font7.resolve(font8);
324 QCOMPARE(font7.families(), QStringList({"Helvetica", "Arial"}));
325 QCOMPARE(font7.family(), "Helvetica");
326}
327
328#ifndef QT_NO_WIDGETS
329void tst_QFont::resetFont()
330{
331 QWidget parent;
332 QWidget firstChild(&parent);
333 QFont parentFont = parent.font();
334 parentFont.setPointSize(parentFont.pointSize() + 2);
335 parent.setFont(parentFont);
336
337 QFont childFont = firstChild.font();
338 childFont.setBold(!childFont.bold());
339 firstChild.setFont(childFont);
340
341 QWidget secondChild(&parent);
342 secondChild.setFont(childFont);
343
344 QVERIFY(parentFont.resolve() != 0);
345 QVERIFY(childFont.resolve() != 0);
346 QVERIFY(childFont != parentFont);
347
348 // reset font on both children
349 firstChild.setFont(QFont());
350 secondChild.setFont(QFont());
351
352 QCOMPARE(firstChild.font().resolve(), QFont::SizeResolved);
353 QCOMPARE(secondChild.font().resolve(), QFont::SizeResolved);
354#ifdef Q_OS_ANDROID
355 QEXPECT_FAIL("", "QTBUG-69214", Continue);
356#endif
357 QCOMPARE(firstChild.font().pointSize(), parent.font().pointSize());
358 QCOMPARE(secondChild.font().pointSize(), parent.font().pointSize());
359 QVERIFY(parent.font().resolve() != 0);
360}
361#endif
362
363void tst_QFont::isCopyOf()
364{
365 QFont font;
366 QVERIFY(font.isCopyOf(QGuiApplication::font()));
367
368 QFont font2("bogusfont", 23);
369 QVERIFY(! font2.isCopyOf(QGuiApplication::font()));
370
371 QFont font3 = font;
372 QVERIFY(font3.isCopyOf(font));
373
374 font3.setPointSize(256);
375 QVERIFY(!font3.isCopyOf(font));
376 font3.setPointSize(font.pointSize());
377 QVERIFY(!font3.isCopyOf(font));
378}
379
380void tst_QFont::insertAndRemoveSubstitutions()
381{
382 QFont::removeSubstitutions("BogusFontFamily");
383 // make sure it is empty before we start
384 QVERIFY(QFont::substitutes("BogusFontFamily").isEmpty());
385 QVERIFY(QFont::substitutes("bogusfontfamily").isEmpty());
386
387 // inserting Foo
388 QFont::insertSubstitution("BogusFontFamily", "Foo");
389 QCOMPARE(QFont::substitutes("BogusFontFamily").count(), 1);
390 QCOMPARE(QFont::substitutes("bogusfontfamily").count(), 1);
391
392 // inserting Bar and Baz
393 QStringList moreFonts;
394 moreFonts << "Bar" << "Baz";
395 QFont::insertSubstitutions("BogusFontFamily", moreFonts);
396 QCOMPARE(QFont::substitutes("BogusFontFamily").count(), 3);
397 QCOMPARE(QFont::substitutes("bogusfontfamily").count(), 3);
398
399 QFont::removeSubstitutions("BogusFontFamily");
400 // make sure it is empty again
401 QVERIFY(QFont::substitutes("BogusFontFamily").isEmpty());
402 QVERIFY(QFont::substitutes("bogusfontfamily").isEmpty());
403}
404
405Q_DECLARE_METATYPE(QDataStream::Version)
406
407void tst_QFont::serialize_data()
408{
409 QTest::addColumn<QFont>(name: "font");
410 // The version in which the tested feature was added.
411 QTest::addColumn<QDataStream::Version>(name: "minimumStreamVersion");
412
413 QFont basicFont;
414 // Versions <= Qt 2.1 had broken point size serialization,
415 // so we set an integer point size.
416 basicFont.setPointSize(9);
417 // Versions <= Qt 5.4 didn't serialize styleName, so clear it
418 basicFont.setStyleName(QString());
419
420 QFont font = basicFont;
421 QTest::newRow(dataTag: "defaultConstructed") << font << QDataStream::Qt_1_0;
422
423 font.setLetterSpacing(type: QFont::AbsoluteSpacing, spacing: 105);
424 QTest::newRow(dataTag: "letterSpacing") << font << QDataStream::Qt_4_5;
425
426 font = basicFont;
427 font.setWordSpacing(50.0);
428 QTest::newRow(dataTag: "wordSpacing") << font << QDataStream::Qt_4_5;
429
430 font = basicFont;
431 font.setPointSize(20);
432 QTest::newRow(dataTag: "pointSize") << font << QDataStream::Qt_1_0;
433
434 font = basicFont;
435 font.setPixelSize(32);
436 QTest::newRow(dataTag: "pixelSize") << font << QDataStream::Qt_3_0;
437
438 font = basicFont;
439 font.setStyleHint(QFont::Monospace);
440 QTest::newRow(dataTag: "styleHint") << font << QDataStream::Qt_1_0;
441
442 font = basicFont;
443 font.setStretch(4000);
444 QTest::newRow(dataTag: "stretch") << font << QDataStream::Qt_4_3;
445
446 font = basicFont;
447 font.setWeight(99);
448 QTest::newRow(dataTag: "weight") << font << QDataStream::Qt_1_0;
449
450 font = basicFont;
451 font.setUnderline(true);
452 QTest::newRow(dataTag: "underline") << font << QDataStream::Qt_1_0;
453
454 font = basicFont;
455 font.setStrikeOut(true);
456 QTest::newRow(dataTag: "strikeOut") << font << QDataStream::Qt_1_0;
457
458 font = basicFont;
459 font.setFixedPitch(true);
460 // This fails for versions less than this, as ignorePitch is set to false
461 // whenever setFixedPitch() is called, but ignorePitch is considered an
462 // extended bit, which were apparently not available until 4.4.
463 QTest::newRow(dataTag: "fixedPitch") << font << QDataStream::Qt_4_4;
464
465 font = basicFont;
466 font.setLetterSpacing(type: QFont::AbsoluteSpacing, spacing: 10);
467 // Fails for 4.4 because letterSpacing wasn't read until 4.5.
468 QTest::newRow(dataTag: "letterSpacing") << font << QDataStream::Qt_4_5;
469
470 font = basicFont;
471 font.setKerning(false);
472 QTest::newRow(dataTag: "kerning") << font << QDataStream::Qt_4_0;
473
474 font = basicFont;
475 font.setStyleStrategy(QFont::NoFontMerging);
476 // This wasn't read properly until 5.4.
477 QTest::newRow(dataTag: "styleStrategy") << font << QDataStream::Qt_5_4;
478
479 font = basicFont;
480 font.setHintingPreference(QFont::PreferFullHinting);
481 // This wasn't read until 5.4.
482 QTest::newRow(dataTag: "hintingPreference") << font << QDataStream::Qt_5_4;
483
484 font = basicFont;
485 font.setStyleName("Regular Black Condensed");
486 // This wasn't read until 5.4.
487 QTest::newRow(dataTag: "styleName") << font << QDataStream::Qt_5_4;
488
489 font = basicFont;
490 font.setCapitalization(QFont::AllUppercase);
491 // This wasn't read until 5.6.
492 QTest::newRow(dataTag: "capitalization") << font << QDataStream::Qt_5_6;
493}
494
495void tst_QFont::serialize()
496{
497 QFETCH(QFont, font);
498 QFETCH(QDataStream::Version, minimumStreamVersion);
499
500 QDataStream stream;
501 const int thisVersion = stream.version();
502
503 for (int version = minimumStreamVersion; version <= thisVersion; ++version) {
504 QBuffer buffer;
505 buffer.open(openMode: QIODevice::WriteOnly);
506 stream.setDevice(&buffer);
507 stream.setVersion(version);
508 stream << font;
509 buffer.close();
510
511 buffer.open(openMode: QIODevice::ReadOnly);
512 QFont readFont;
513 stream >> readFont;
514 QVERIFY2(readFont == font, qPrintable(QString::fromLatin1("Fonts do not compare equal for QDataStream version ") +
515 QString::fromLatin1("%1:\nactual: %2\nexpected: %3").arg(version).arg(readFont.toString()).arg(font.toString())));
516 }
517}
518
519#if QT_DEPRECATED_SINCE(5, 13)
520// QFont::lastResortFont() may abort with qFatal() on QWS/QPA
521// if absolutely no font is found. Just as ducumented for QFont::lastResortFont().
522// This happens on our CI machines which run QWS autotests.
523// ### fixme: Check platforms
524void tst_QFont::lastResortFont()
525{
526 QSKIP("QFont::lastResortFont() may abort with qFatal() on QPA, QTBUG-22325");
527 QFont font;
528 QVERIFY(!font.lastResortFont().isEmpty());
529}
530#endif
531
532void tst_QFont::styleName()
533{
534#if !defined(Q_OS_MAC)
535 QSKIP("Only tested on Mac");
536#else
537 QFont font("Helvetica Neue");
538 font.setStyleName("UltraLight");
539
540 QCOMPARE(QFontInfo(font).styleName(), QString("UltraLight"));
541#endif
542}
543
544QString getPlatformGenericFont(const char* genericName)
545{
546#if defined(Q_OS_UNIX) && !defined(QT_NO_FONTCONFIG) && QT_CONFIG(process)
547 QProcess p;
548 p.start(program: QLatin1String("fc-match"), arguments: (QStringList() << "-f%{family}" << genericName));
549 if (!p.waitForStarted())
550 qWarning(msg: "fc-match cannot be started: %s", qPrintable(p.errorString()));
551 if (p.waitForFinished())
552 return QString::fromLatin1(str: p.readAllStandardOutput());
553#endif
554 return QLatin1String(genericName);
555}
556
557static inline QByteArray msgNotAcceptableFont(const QString &defaultFamily, const QStringList &acceptableFamilies)
558{
559 QString res = QString::fromLatin1(str: "Font family '%1' is not one of the following acceptable results: ").arg(a: defaultFamily);
560 Q_FOREACH (const QString &family, acceptableFamilies)
561 res += QLatin1String("\n ") + family;
562 return res.toLocal8Bit();
563}
564
565Q_DECLARE_METATYPE(QFont::StyleHint)
566void tst_QFont::defaultFamily_data()
567{
568 QTest::addColumn<QFont::StyleHint>(name: "styleHint");
569 QTest::addColumn<QStringList>(name: "acceptableFamilies");
570
571 QTest::newRow(dataTag: "serif") << QFont::Serif << (QStringList() << "Times New Roman" << "Times" << "Droid Serif" << getPlatformGenericFont(genericName: "serif").split(sep: ","));
572 QTest::newRow(dataTag: "monospace") << QFont::Monospace << (QStringList() << "Courier New" << "Monaco" << "Menlo" << "Droid Sans Mono" << getPlatformGenericFont(genericName: "monospace").split(sep: ","));
573 QTest::newRow(dataTag: "cursive") << QFont::Cursive << (QStringList() << "Comic Sans MS" << "Apple Chancery" << "Roboto" << "Droid Sans" << getPlatformGenericFont(genericName: "cursive").split(sep: ","));
574 QTest::newRow(dataTag: "fantasy") << QFont::Fantasy << (QStringList() << "Impact" << "Zapfino" << "Roboto" << "Droid Sans" << getPlatformGenericFont(genericName: "fantasy").split(sep: ","));
575 QTest::newRow(dataTag: "sans-serif") << QFont::SansSerif << (QStringList() << "Arial" << "Lucida Grande" << "Helvetica" << "Roboto" << "Droid Sans" << "Segoe UI" << getPlatformGenericFont(genericName: "sans-serif").split(sep: ","));
576}
577
578void tst_QFont::defaultFamily()
579{
580 QFETCH(QFont::StyleHint, styleHint);
581 QFETCH(QStringList, acceptableFamilies);
582
583 QFont f;
584 QFontDatabase db;
585 f.setStyleHint(styleHint);
586 const QString familyForHint(f.defaultFamily());
587
588 // it should at least return a family that is available.
589 QVERIFY(db.hasFamily(familyForHint));
590
591 bool isAcceptable = false;
592 Q_FOREACH (const QString& family, acceptableFamilies) {
593 if (!familyForHint.compare(s: family, cs: Qt::CaseInsensitive)) {
594 isAcceptable = true;
595 break;
596 }
597 }
598
599#ifdef Q_OS_ANDROID
600 QEXPECT_FAIL("serif", "QTBUG-69215", Continue);
601#endif
602 QVERIFY2(isAcceptable, msgNotAcceptableFont(familyForHint, acceptableFamilies));
603}
604
605void tst_QFont::toAndFromString()
606{
607 QFont defaultFont = QGuiApplication::font();
608 QString family = defaultFont.family();
609
610 QFontDatabase fdb;
611 const QStringList stylesList = fdb.styles(family);
612 if (stylesList.size() == 0)
613 QSKIP("Default font doesn't have any styles");
614
615 for (const QString &style : stylesList) {
616 QFont result;
617 QFont initial = fdb.font(family, style, pointSize: defaultFont.pointSize());
618
619 result.fromString(initial.toString());
620
621 QCOMPARE(result, initial);
622 }
623}
624
625void tst_QFont::fromStringWithoutStyleName()
626{
627 QFont font1;
628 font1.fromString("Noto Sans,12,-1,5,50,0,0,0,0,0,Regular");
629
630 QFont font2 = font1;
631 const QString str = "Times,16,-1,5,50,0,0,0,0,0";
632 font2.fromString(str);
633
634 QCOMPARE(font2.toString(), str);
635}
636
637void tst_QFont::fromDegenerateString_data()
638{
639 QTest::addColumn<QString>(name: "string");
640
641 QTest::newRow(dataTag: "empty") << QString();
642 QTest::newRow(dataTag: "justAComma") << ",";
643 QTest::newRow(dataTag: "commasAndSpaces") << " , , ";
644 QTest::newRow(dataTag: "spaces") << " ";
645 QTest::newRow(dataTag: "spacesTabsAndNewlines") << " \t \n";
646}
647
648void tst_QFont::fromDegenerateString()
649{
650 QFETCH(QString, string);
651 QFont f;
652 QTest::ignoreMessage(type: QtWarningMsg, messagePattern: QRegularExpression(".*Invalid description.*"));
653 QCOMPARE(f.fromString(string), false);
654 QCOMPARE(f, QFont());
655}
656
657void tst_QFont::sharing()
658{
659 // QFontCache references the engineData
660 int refs_by_cache = 1;
661
662 QFont f;
663 f.setStyleHint(QFont::Serif);
664 f.exactMatch(); // loads engine
665 QCOMPARE(QFontPrivate::get(f)->ref.loadRelaxed(), 1);
666 QVERIFY(QFontPrivate::get(f)->engineData);
667 QCOMPARE(QFontPrivate::get(f)->engineData->ref.loadRelaxed(), 1 + refs_by_cache);
668
669 QFont f2(f);
670 QCOMPARE(QFontPrivate::get(f2), QFontPrivate::get(f));
671 QCOMPARE(QFontPrivate::get(f2)->ref.loadRelaxed(), 2);
672 QVERIFY(QFontPrivate::get(f2)->engineData);
673 QCOMPARE(QFontPrivate::get(f2)->engineData, QFontPrivate::get(f)->engineData);
674 QCOMPARE(QFontPrivate::get(f2)->engineData->ref.loadRelaxed(), 1 + refs_by_cache);
675
676 f2.setKerning(!f.kerning());
677 QVERIFY(QFontPrivate::get(f2) != QFontPrivate::get(f));
678 QCOMPARE(QFontPrivate::get(f2)->ref.loadRelaxed(), 1);
679 QVERIFY(QFontPrivate::get(f2)->engineData);
680 QCOMPARE(QFontPrivate::get(f2)->engineData, QFontPrivate::get(f)->engineData);
681 QCOMPARE(QFontPrivate::get(f2)->engineData->ref.loadRelaxed(), 2 + refs_by_cache);
682
683 f2 = f;
684 QCOMPARE(QFontPrivate::get(f2), QFontPrivate::get(f));
685 QCOMPARE(QFontPrivate::get(f2)->ref.loadRelaxed(), 2);
686 QVERIFY(QFontPrivate::get(f2)->engineData);
687 QCOMPARE(QFontPrivate::get(f2)->engineData, QFontPrivate::get(f)->engineData);
688 QCOMPARE(QFontPrivate::get(f2)->engineData->ref.loadRelaxed(), 1 + refs_by_cache);
689
690 if (f.pointSize() > 0)
691 f2.setPointSize(f.pointSize() * 2 / 3);
692 else
693 f2.setPixelSize(f.pixelSize() * 2 / 3);
694 QVERIFY(QFontPrivate::get(f2) != QFontPrivate::get(f));
695 QCOMPARE(QFontPrivate::get(f2)->ref.loadRelaxed(), 1);
696 QVERIFY(!QFontPrivate::get(f2)->engineData);
697 QVERIFY(QFontPrivate::get(f2)->engineData != QFontPrivate::get(f)->engineData);
698}
699
700void tst_QFont::familyNameWithCommaQuote_data()
701{
702 QTest::addColumn<QString>(name: "familyName");
703 QTest::addColumn<QString>(name: "chosenFamilyName");
704
705 const QString standardFont(QFont().defaultFamily());
706 if (standardFont.isEmpty())
707 QSKIP("No default font available on the system");
708 const QString weirdFont(QLatin1String("'My, weird'' font name',"));
709 const QString commaSeparated(standardFont + QLatin1String(",Times New Roman"));
710 const QString commaSeparatedWeird(weirdFont + QLatin1String(",") + standardFont);
711 const QString commaSeparatedBogus(QLatin1String("BogusFont,") + standardFont);
712
713 QTest::newRow(dataTag: "standard") << standardFont << standardFont;
714 QTest::newRow(dataTag: "weird") << weirdFont << weirdFont;
715 QTest::newRow(dataTag: "commaSeparated") << commaSeparated << standardFont;
716 QTest::newRow(dataTag: "commaSeparatedWeird") << commaSeparatedWeird << weirdFont;
717 QTest::newRow(dataTag: "commaSeparatedBogus") << commaSeparatedBogus << standardFont;
718}
719
720void tst_QFont::familyNameWithCommaQuote()
721{
722 QFETCH(QString, familyName);
723 QFETCH(QString, chosenFamilyName);
724
725 const int weirdFontId = QFontDatabase::addApplicationFont(fileName: ":/weirdfont.otf");
726
727 QVERIFY(weirdFontId != -1);
728 QFont f(familyName);
729 QCOMPARE(f.family(), familyName);
730 QCOMPARE(QFontInfo(f).family(), chosenFamilyName);
731
732 QFontDatabase::removeApplicationFont(id: weirdFontId);
733}
734
735void tst_QFont::setFamilies_data()
736{
737 QTest::addColumn<QStringList>(name: "families");
738 QTest::addColumn<QString>(name: "chosenFamilyName");
739
740 const QString weirdFont(QLatin1String("'My, weird'' font name',"));
741 const QString standardFont(QFont().defaultFamily());
742 if (standardFont.isEmpty())
743 QSKIP("No default font available on the system");
744
745 QTest::newRow(dataTag: "standard") << (QStringList() << standardFont) << standardFont;
746 QTest::newRow(dataTag: "weird") << (QStringList() << weirdFont) << weirdFont;
747 QTest::newRow(dataTag: "standard-weird") << (QStringList() << standardFont << weirdFont) << standardFont;
748 QTest::newRow(dataTag: "weird-standard") << (QStringList() << weirdFont << standardFont) << weirdFont;
749 QTest::newRow(dataTag: "nonexist-weird") << (QStringList() << "NonExistentFont" << weirdFont) << weirdFont;
750}
751
752void tst_QFont::setFamilies()
753{
754 QFETCH(QStringList, families);
755 QFETCH(QString, chosenFamilyName);
756
757 const int weirdFontId = QFontDatabase::addApplicationFont(fileName: ":/weirdfont.otf");
758
759 QVERIFY(weirdFontId != -1);
760 QFont f;
761 f.setFamilies(families);
762 QCOMPARE(QFontInfo(f).family(), chosenFamilyName);
763
764 QFontDatabase::removeApplicationFont(id: weirdFontId);
765}
766
767void tst_QFont::setFamiliesAndFamily_data()
768{
769 QTest::addColumn<QStringList>(name: "families");
770 QTest::addColumn<QString>(name: "family");
771 QTest::addColumn<QString>(name: "chosenFamilyName");
772
773 const QString weirdFont(QLatin1String("'My, weird'' font name',"));
774 const QString defaultFont(QFont().defaultFamily());
775 if (defaultFont.isEmpty())
776 QSKIP("No default font available on the system");
777
778 const QString timesFont(QLatin1String("Times"));
779 const QString nonExistFont(QLatin1String("NonExistentFont"));
780
781 QTest::newRow(dataTag: "firstInFamilies") << (QStringList() << defaultFont << timesFont) << weirdFont << defaultFont;
782 QTest::newRow(dataTag: "secondInFamilies") << (QStringList() << nonExistFont << weirdFont) << defaultFont << weirdFont;
783 QTest::newRow(dataTag: "family") << (QStringList() << nonExistFont) << defaultFont << defaultFont;
784}
785
786void tst_QFont::setFamiliesAndFamily()
787{
788 QFETCH(QStringList, families);
789 QFETCH(QString, family);
790 QFETCH(QString, chosenFamilyName);
791
792 const int weirdFontId = QFontDatabase::addApplicationFont(fileName: ":/weirdfont.otf");
793
794 QVERIFY(weirdFontId != -1);
795 QFont f;
796 f.setFamilies(families);
797 f.setFamily(family);
798 QCOMPARE(QFontInfo(f).family(), chosenFamilyName);
799
800 QFontDatabase::removeApplicationFont(id: weirdFontId);
801}
802
803QTEST_MAIN(tst_QFont)
804#include "tst_qfont.moc"
805

source code of qtbase/tests/auto/gui/text/qfont/tst_qfont.cpp