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 | |
44 | class tst_QFont : public QObject |
45 | { |
46 | Q_OBJECT |
47 | |
48 | private 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 |
82 | void 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 | |
118 | void 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 | |
154 | void 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 | |
186 | void 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 | |
267 | void 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 |
329 | void 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 | |
363 | void 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 | |
380 | void 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 | |
405 | Q_DECLARE_METATYPE(QDataStream::Version) |
406 | |
407 | void 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 | |
495 | void 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 |
524 | void 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 | |
532 | void 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 | |
544 | QString 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 | |
557 | static 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 | |
565 | Q_DECLARE_METATYPE(QFont::StyleHint) |
566 | void 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 | |
578 | void 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 | |
605 | void 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 | |
625 | void 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 | |
637 | void 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 | |
648 | void 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 | |
657 | void 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 | |
700 | void 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 | |
720 | void 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 | |
735 | void 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 | |
752 | void 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 | |
767 | void 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 | |
786 | void 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 | |
803 | QTEST_MAIN(tst_QFont) |
804 | #include "tst_qfont.moc" |
805 | |