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 | #include <QtTest/QtTest> |
30 | #include <QtGui/QGuiApplication> |
31 | #include <QtGui/QPainter> |
32 | #include <QtGui/QImage> |
33 | |
34 | #include <qstatictext.h> |
35 | #include <qpaintengine.h> |
36 | |
37 | #ifdef QT_BUILD_INTERNAL |
38 | #include <private/qstatictext_p.h> |
39 | #endif |
40 | |
41 | // #define DEBUG_SAVE_IMAGE |
42 | |
43 | static inline QImage blankSquare() |
44 | { |
45 | // a "blank" square; we compare against in our testfunctions to verify |
46 | // that we have actually painted something |
47 | QPixmap pm(1000, 1000); |
48 | pm.fill(fillColor: Qt::white); |
49 | return pm.toImage(); |
50 | } |
51 | |
52 | class tst_QStaticText: public QObject |
53 | { |
54 | Q_OBJECT |
55 | public: |
56 | tst_QStaticText() : m_whiteSquare(blankSquare()) {} |
57 | |
58 | private slots: |
59 | void constructionAndDestruction(); |
60 | void drawToPoint_data(); |
61 | void drawToPoint(); |
62 | void drawToRect_data(); |
63 | void drawToRect(); |
64 | void compareToDrawText_data(); |
65 | void compareToDrawText(); |
66 | void setFont(); |
67 | void setTextWidth(); |
68 | void prepareToCorrectData(); |
69 | void prepareToWrongData(); |
70 | |
71 | void copyConstructor(); |
72 | |
73 | void translatedPainter(); |
74 | void rotatedPainter(); |
75 | void scaledPainter(); |
76 | void projectedPainter(); |
77 | #if 0 |
78 | void rotatedScaledAndTranslatedPainter_data(); |
79 | void rotatedScaledAndTranslatedPainter(); |
80 | #endif |
81 | void transformationChanged(); |
82 | |
83 | void plainTextVsRichText(); |
84 | |
85 | void setPenPlainText_data(); |
86 | void setPenPlainText(); |
87 | void setPenRichText(); |
88 | void richTextOverridesPen(); |
89 | |
90 | void drawStruckOutText(); |
91 | void drawOverlinedText(); |
92 | void drawUnderlinedText(); |
93 | |
94 | void unprintableCharacter_qtbug12614(); |
95 | |
96 | #ifdef QT_BUILD_INTERNAL |
97 | void underlinedColor_qtbug20159(); |
98 | void textDocumentColor(); |
99 | #endif |
100 | |
101 | void multiLine(); |
102 | |
103 | void size_qtbug65836(); |
104 | |
105 | private: |
106 | bool supportsTransformations() const; |
107 | |
108 | const QImage m_whiteSquare; |
109 | }; |
110 | |
111 | Q_DECLARE_METATYPE(QImage::Format); |
112 | |
113 | void tst_QStaticText::constructionAndDestruction() |
114 | { |
115 | QStaticText text("My text" ); |
116 | } |
117 | |
118 | void tst_QStaticText::copyConstructor() |
119 | { |
120 | QStaticText text(QLatin1String("My text" )); |
121 | |
122 | QTextOption textOption(Qt::AlignRight); |
123 | text.setTextOption(textOption); |
124 | |
125 | text.setPerformanceHint(QStaticText::AggressiveCaching); |
126 | text.setTextWidth(123.456); |
127 | text.setTextFormat(Qt::PlainText); |
128 | |
129 | QStaticText copiedText(text); |
130 | copiedText.setText(QLatin1String("Other text" )); |
131 | |
132 | QCOMPARE(copiedText.textOption().alignment(), Qt::AlignRight); |
133 | QCOMPARE(copiedText.performanceHint(), QStaticText::AggressiveCaching); |
134 | QCOMPARE(copiedText.textWidth(), 123.456); |
135 | QCOMPARE(copiedText.textFormat(), Qt::PlainText); |
136 | |
137 | QStaticText otherCopiedText(copiedText); |
138 | otherCopiedText.setTextWidth(789); |
139 | |
140 | QCOMPARE(otherCopiedText.text(), QString::fromLatin1("Other text" )); |
141 | } |
142 | |
143 | Q_DECLARE_METATYPE(QStaticText::PerformanceHint) |
144 | void tst_QStaticText::drawToPoint_data() |
145 | { |
146 | QTest::addColumn<QStaticText::PerformanceHint>(name: "performanceHint" ); |
147 | |
148 | QTest::newRow(dataTag: "Moderate caching" ) << QStaticText::ModerateCaching; |
149 | QTest::newRow(dataTag: "Aggressive caching" ) << QStaticText::AggressiveCaching; |
150 | } |
151 | |
152 | void tst_QStaticText::drawToPoint() |
153 | { |
154 | QFETCH(QStaticText::PerformanceHint, performanceHint); |
155 | |
156 | QPixmap imageDrawText(1000, 1000); |
157 | imageDrawText.fill(fillColor: Qt::white); |
158 | { |
159 | QPainter p(&imageDrawText); |
160 | p.drawText(x: 11, y: 12, s: "Lorem ipsum dolor sit amet, consectetur adipiscing elit." ); |
161 | } |
162 | |
163 | QPixmap imageDrawStaticText(1000, 1000); |
164 | imageDrawStaticText.fill(fillColor: Qt::white); |
165 | { |
166 | QPainter p(&imageDrawStaticText); |
167 | QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit." ); |
168 | text.setTextFormat(Qt::PlainText); |
169 | text.setPerformanceHint(performanceHint); |
170 | p.drawStaticText(topLeftPosition: QPointF(11, 12 - QFontMetricsF(p.font()).ascent()), staticText: text); |
171 | } |
172 | |
173 | QVERIFY(imageDrawText.toImage() != m_whiteSquare); |
174 | QCOMPARE(imageDrawStaticText, imageDrawText); |
175 | } |
176 | |
177 | void tst_QStaticText::drawToRect_data() |
178 | { |
179 | QTest::addColumn<QStaticText::PerformanceHint>(name: "performanceHint" ); |
180 | |
181 | QTest::newRow(dataTag: "Moderate caching" ) << QStaticText::ModerateCaching; |
182 | QTest::newRow(dataTag: "Aggressive caching" ) << QStaticText::AggressiveCaching; |
183 | } |
184 | |
185 | void tst_QStaticText::drawToRect() |
186 | { |
187 | QFETCH(QStaticText::PerformanceHint, performanceHint); |
188 | |
189 | QPixmap imageDrawText(1000, 1000); |
190 | imageDrawText.fill(fillColor: Qt::white); |
191 | { |
192 | QPainter p(&imageDrawText); |
193 | p.drawText(r: QRectF(11, 12, 10, 500), text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit." ); |
194 | } |
195 | |
196 | QPixmap imageDrawStaticText(1000, 1000); |
197 | imageDrawStaticText.fill(fillColor: Qt::white); |
198 | { |
199 | QPainter p(&imageDrawStaticText); |
200 | QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit." ); |
201 | text.setTextWidth(10), |
202 | p.setClipRect(QRectF(11, 12, 10, 500)); |
203 | text.setPerformanceHint(performanceHint); |
204 | text.setTextFormat(Qt::PlainText); |
205 | p.drawStaticText(topLeftPosition: QPointF(11, 12), staticText: text); |
206 | } |
207 | |
208 | #if defined(DEBUG_SAVE_IMAGE) |
209 | imageDrawText.save("drawToRect_imageDrawText.png" ); |
210 | imageDrawStaticText.save("drawToRect_imageDrawStaticText.png" ); |
211 | #endif |
212 | |
213 | QVERIFY(imageDrawText.toImage() != m_whiteSquare); |
214 | QCOMPARE(imageDrawStaticText, imageDrawText); |
215 | } |
216 | |
217 | void tst_QStaticText::compareToDrawText_data() |
218 | { |
219 | QTest::addColumn<QFont>(name: "font" ); |
220 | |
221 | QTest::newRow(dataTag: "default" ) << QFont(); |
222 | QFont sansserif; sansserif.setStyleHint(QFont::SansSerif); |
223 | QFont serif; serif.setStyleHint(QFont::Serif); |
224 | QFont monospace; monospace.setStyleHint(QFont::Monospace); |
225 | QTest::newRow(dataTag: "sans-serif" ) << QFont(sansserif.defaultFamily()); |
226 | QTest::newRow(dataTag: "serif" ) << QFont(serif.defaultFamily()); |
227 | QTest::newRow(dataTag: "monospace" ) << QFont(monospace.defaultFamily()); |
228 | } |
229 | |
230 | void tst_QStaticText::compareToDrawText() |
231 | { |
232 | QFETCH(QFont, font); |
233 | |
234 | QPixmap imageDrawText(1000, 1000); |
235 | imageDrawText.fill(fillColor: Qt::white); |
236 | { |
237 | QPainter p(&imageDrawText); |
238 | p.setFont(font); |
239 | p.drawText(r: QRectF(11, 12, 30, 500), text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit." ); |
240 | } |
241 | |
242 | QPixmap imageDrawStaticPlainText(1000, 1000); |
243 | imageDrawStaticPlainText.fill(fillColor: Qt::white); |
244 | { |
245 | QPainter p(&imageDrawStaticPlainText); |
246 | p.setFont(font); |
247 | QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit." ); |
248 | text.setTextWidth(10), |
249 | p.setClipRect(QRectF(11, 12, 30, 500)); |
250 | text.setTextFormat(Qt::PlainText); |
251 | p.drawStaticText(topLeftPosition: QPointF(11, 12), staticText: text); |
252 | } |
253 | |
254 | QPixmap imageDrawStaticRichText(1000, 1000); |
255 | imageDrawStaticRichText.fill(fillColor: Qt::white); |
256 | { |
257 | QPainter p(&imageDrawStaticRichText); |
258 | p.setFont(font); |
259 | QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit." ); |
260 | text.setTextWidth(10), |
261 | p.setClipRect(QRectF(11, 12, 30, 500)); |
262 | text.setTextFormat(Qt::RichText); |
263 | p.drawStaticText(topLeftPosition: QPointF(11, 12), staticText: text); |
264 | } |
265 | |
266 | #if defined(DEBUG_SAVE_IMAGE) |
267 | imageDrawText.save("compareToDrawText_imageDrawText.png" ); |
268 | imageDrawStaticText.save("compareToDrawText_imageDrawStaticPlainText.png" ); |
269 | imageDrawStaticText.save("compareToDrawText_imageDrawStaticRichText.png" ); |
270 | #endif |
271 | |
272 | QVERIFY(imageDrawText.toImage() != m_whiteSquare); |
273 | QCOMPARE(imageDrawStaticPlainText, imageDrawText); |
274 | QCOMPARE(imageDrawStaticRichText, imageDrawText); |
275 | } |
276 | |
277 | void tst_QStaticText::prepareToCorrectData() |
278 | { |
279 | QTransform transform; |
280 | transform.scale(sx: 2.0, sy: 2.0); |
281 | transform.translate(dx: 100, dy: 10); |
282 | transform.rotate(a: 90, axis: Qt::ZAxis); |
283 | |
284 | QPixmap imageDrawText(1000, 1000); |
285 | imageDrawText.fill(fillColor: Qt::white); |
286 | { |
287 | QPainter p(&imageDrawText); |
288 | p.setTransform(transform); |
289 | p.drawText(x: 11, y: 12, s: "Lorem ipsum dolor sit amet, consectetur adipiscing elit." ); |
290 | } |
291 | |
292 | QPixmap imageDrawStaticText(1000, 1000); |
293 | imageDrawStaticText.fill(fillColor: Qt::white); |
294 | { |
295 | QPainter p(&imageDrawStaticText); |
296 | p.setTransform(transform); |
297 | QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit." ); |
298 | text.prepare(matrix: transform, font: p.font()); |
299 | text.setTextFormat(Qt::PlainText); |
300 | p.drawStaticText(topLeftPosition: QPointF(11, 12 - QFontMetricsF(p.font()).ascent()), staticText: text); |
301 | } |
302 | |
303 | #if defined(DEBUG_SAVE_IMAGE) |
304 | imageDrawText.save("prepareToCorrectData_imageDrawText.png" ); |
305 | imageDrawStaticText.save("prepareToCorrectData_imageDrawStaticText.png" ); |
306 | #endif |
307 | |
308 | QVERIFY(imageDrawText.toImage() != m_whiteSquare); |
309 | |
310 | if (!supportsTransformations()) |
311 | QEXPECT_FAIL("" , "Graphics system does not support transformed text on this platform" , Abort); |
312 | QCOMPARE(imageDrawStaticText, imageDrawText); |
313 | } |
314 | |
315 | void tst_QStaticText::prepareToWrongData() |
316 | { |
317 | QTransform transform; |
318 | transform.scale(sx: 2.0, sy: 2.0); |
319 | transform.rotate(a: 90, axis: Qt::ZAxis); |
320 | |
321 | QPixmap imageDrawText(1000, 1000); |
322 | imageDrawText.fill(fillColor: Qt::white); |
323 | { |
324 | QPainter p(&imageDrawText); |
325 | p.drawText(x: 11, y: 12, s: "Lorem ipsum dolor sit amet, consectetur adipiscing elit." ); |
326 | } |
327 | |
328 | QPixmap imageDrawStaticText(1000, 1000); |
329 | imageDrawStaticText.fill(fillColor: Qt::white); |
330 | { |
331 | QPainter p(&imageDrawStaticText); |
332 | QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit." ); |
333 | text.prepare(matrix: transform, font: p.font()); |
334 | text.setTextFormat(Qt::PlainText); |
335 | p.drawStaticText(topLeftPosition: QPointF(11, 12 - QFontMetricsF(p.font()).ascent()), staticText: text); |
336 | } |
337 | |
338 | QVERIFY(imageDrawText.toImage() != m_whiteSquare); |
339 | QCOMPARE(imageDrawStaticText, imageDrawText); |
340 | } |
341 | |
342 | |
343 | void tst_QStaticText::setFont() |
344 | { |
345 | QFont font = QGuiApplication::font(); |
346 | font.setBold(true); |
347 | font.setPointSize(28); |
348 | |
349 | QPixmap imageDrawText(1000, 1000); |
350 | imageDrawText.fill(fillColor: Qt::white); |
351 | { |
352 | QPainter p(&imageDrawText); |
353 | p.drawText(r: QRectF(0, 0, 1000, 1000), flags: 0, text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit." ); |
354 | |
355 | p.setFont(font); |
356 | p.drawText(r: QRectF(11, 120, 1000, 1000), flags: 0, text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit." ); |
357 | } |
358 | |
359 | QPixmap imageDrawStaticText(1000, 1000); |
360 | imageDrawStaticText.fill(fillColor: Qt::white); |
361 | { |
362 | QPainter p(&imageDrawStaticText); |
363 | |
364 | QStaticText text; |
365 | text.setText("Lorem ipsum dolor sit amet, consectetur adipiscing elit." ); |
366 | text.setTextFormat(Qt::PlainText); |
367 | |
368 | p.drawStaticText(x: 0, y: 0, staticText: text); |
369 | |
370 | p.setFont(font); |
371 | p.drawStaticText(x: 11, y: 120, staticText: text); |
372 | } |
373 | |
374 | #if defined(DEBUG_SAVE_IMAGE) |
375 | imageDrawText.save("setFont_imageDrawText.png" ); |
376 | imageDrawStaticText.save("setFont_imageDrawStaticText.png" ); |
377 | #endif |
378 | |
379 | QVERIFY(imageDrawText.toImage() != m_whiteSquare); |
380 | QCOMPARE(imageDrawStaticText, imageDrawText); |
381 | } |
382 | |
383 | void tst_QStaticText::setTextWidth() |
384 | { |
385 | QPixmap imageDrawText(1000, 1000); |
386 | imageDrawText.fill(fillColor: Qt::white); |
387 | { |
388 | QPainter p(&imageDrawText); |
389 | p.drawText(r: QRectF(11, 12, 10, 500), text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit." ); |
390 | } |
391 | |
392 | QPixmap imageDrawStaticText(1000, 1000); |
393 | imageDrawStaticText.fill(fillColor: Qt::white); |
394 | { |
395 | QPainter p(&imageDrawStaticText); |
396 | QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit." ); |
397 | text.setTextWidth(10); |
398 | p.setClipRect(QRectF(11, 12, 10, 500)); |
399 | p.drawStaticText(topLeftPosition: QPointF(11, 12), staticText: text); |
400 | } |
401 | |
402 | QVERIFY(imageDrawText.toImage() != m_whiteSquare); |
403 | QCOMPARE(imageDrawStaticText, imageDrawText); |
404 | } |
405 | |
406 | void tst_QStaticText::translatedPainter() |
407 | { |
408 | QPixmap imageDrawText(1000, 1000); |
409 | imageDrawText.fill(fillColor: Qt::white); |
410 | { |
411 | QPainter p(&imageDrawText); |
412 | p.translate(dx: 100, dy: 200); |
413 | |
414 | p.drawText(x: 11, y: 12, s: "Lorem ipsum dolor sit amet, consectetur adipiscing elit." ); |
415 | } |
416 | |
417 | QPixmap imageDrawStaticText(1000, 1000); |
418 | imageDrawStaticText.fill(fillColor: Qt::white); |
419 | { |
420 | QPainter p(&imageDrawStaticText); |
421 | p.translate(dx: 100, dy: 200); |
422 | |
423 | QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit." ); |
424 | text.setTextFormat(Qt::PlainText); |
425 | |
426 | p.drawStaticText(topLeftPosition: QPointF(11, 12 - QFontMetricsF(p.font()).ascent()), staticText: text); |
427 | } |
428 | |
429 | QVERIFY(imageDrawText.toImage() != m_whiteSquare); |
430 | QCOMPARE(imageDrawStaticText, imageDrawText); |
431 | } |
432 | |
433 | bool tst_QStaticText::supportsTransformations() const |
434 | { |
435 | QPixmap pm(10, 10); |
436 | QPainter p(&pm); |
437 | return p.paintEngine()->type() != QPaintEngine::OpenGL; |
438 | } |
439 | |
440 | void tst_QStaticText::rotatedPainter() |
441 | { |
442 | QPixmap imageDrawText(1000, 1000); |
443 | imageDrawText.fill(fillColor: Qt::white); |
444 | { |
445 | QPainter p(&imageDrawText); |
446 | p.rotate(a: 30.0); |
447 | p.drawText(r: QRectF(0, 0, 1000, 100), flags: 0, text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit." ); |
448 | } |
449 | |
450 | QPixmap imageDrawStaticText(1000, 1000); |
451 | imageDrawStaticText.fill(fillColor: Qt::white); |
452 | { |
453 | QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit." ); |
454 | text.setTextFormat(Qt::PlainText); |
455 | |
456 | QPainter p(&imageDrawStaticText); |
457 | p.rotate(a: 30.0); |
458 | p.drawStaticText(p: QPoint(0, 0), staticText: text); |
459 | } |
460 | |
461 | #if defined(DEBUG_SAVE_IMAGE) |
462 | imageDrawText.save("rotatedPainter_imageDrawText.png" ); |
463 | imageDrawStaticText.save("rotatedPainter_imageDrawStaticText.png" ); |
464 | #endif |
465 | |
466 | QVERIFY(imageDrawText.toImage() != m_whiteSquare); |
467 | |
468 | #ifdef Q_OS_ANDROID |
469 | QEXPECT_FAIL("" , "QTBUG-69218" , Continue); |
470 | #endif |
471 | if (!supportsTransformations()) |
472 | QEXPECT_FAIL("" , "Graphics system does not support transformed text on this platform" , Abort); |
473 | QCOMPARE(imageDrawStaticText, imageDrawText); |
474 | } |
475 | |
476 | void tst_QStaticText::scaledPainter() |
477 | { |
478 | QPixmap imageDrawText(1000, 1000); |
479 | imageDrawText.fill(fillColor: Qt::white); |
480 | { |
481 | QPainter p(&imageDrawText); |
482 | p.scale(sx: 2.0, sy: 0.2); |
483 | |
484 | p.drawText(x: 11, y: 12, s: "Lorem ipsum dolor sit amet, consectetur adipiscing elit." ); |
485 | } |
486 | |
487 | QPixmap imageDrawStaticText(1000, 1000); |
488 | imageDrawStaticText.fill(fillColor: Qt::white); |
489 | { |
490 | QPainter p(&imageDrawStaticText); |
491 | p.scale(sx: 2.0, sy: 0.2); |
492 | |
493 | QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit." ); |
494 | text.setTextFormat(Qt::PlainText); |
495 | |
496 | p.drawStaticText(topLeftPosition: QPointF(11, 12 - QFontMetricsF(p.font()).ascent()), staticText: text); |
497 | } |
498 | |
499 | QVERIFY(imageDrawText.toImage() != m_whiteSquare); |
500 | |
501 | if (!supportsTransformations()) |
502 | QEXPECT_FAIL("" , "Graphics system does not support transformed text on this platform" , Abort); |
503 | QCOMPARE(imageDrawStaticText, imageDrawText); |
504 | } |
505 | |
506 | void tst_QStaticText::projectedPainter() |
507 | { |
508 | QTransform transform; |
509 | transform.rotate(a: 90, axis: Qt::XAxis); |
510 | |
511 | QPixmap imageDrawText(1000, 1000); |
512 | imageDrawText.fill(fillColor: Qt::white); |
513 | { |
514 | QPainter p(&imageDrawText); |
515 | p.setTransform(transform); |
516 | |
517 | p.drawText(x: 11, y: 12, s: "Lorem ipsum dolor sit amet, consectetur adipiscing elit." ); |
518 | } |
519 | |
520 | QPixmap imageDrawStaticText(1000, 1000); |
521 | imageDrawStaticText.fill(fillColor: Qt::white); |
522 | { |
523 | QPainter p(&imageDrawStaticText); |
524 | p.setTransform(transform); |
525 | |
526 | QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit." ); |
527 | text.setTextFormat(Qt::PlainText); |
528 | |
529 | p.drawStaticText(topLeftPosition: QPointF(11, 12 - QFontMetricsF(p.font()).ascent()), staticText: text); |
530 | } |
531 | |
532 | QCOMPARE(imageDrawStaticText, imageDrawText); |
533 | } |
534 | |
535 | #if 0 |
536 | void tst_QStaticText::rotatedScaledAndTranslatedPainter_data() |
537 | { |
538 | QTest::addColumn<qreal>("offset" ); |
539 | |
540 | for (int i=0; i<100; ++i) { |
541 | qreal offset = 300 + i / 100.; |
542 | QTest::newRow(QByteArray::number(offset).constData()) << offset; |
543 | } |
544 | } |
545 | |
546 | void tst_QStaticText::rotatedScaledAndTranslatedPainter() |
547 | { |
548 | QFETCH(qreal, offset); |
549 | |
550 | QPixmap imageDrawText(1000, 1000); |
551 | imageDrawText.fill(Qt::white); |
552 | { |
553 | QPainter p(&imageDrawText); |
554 | p.translate(offset, 0); |
555 | p.rotate(45.0); |
556 | p.scale(2.0, 2.0); |
557 | p.translate(100, 200); |
558 | |
559 | p.drawText(11, 12, "Lorem ipsum dolor sit amet, consectetur adipiscing elit." ); |
560 | } |
561 | |
562 | QPixmap imageDrawStaticText(1000, 1000); |
563 | imageDrawStaticText.fill(Qt::white); |
564 | { |
565 | QPainter p(&imageDrawStaticText); |
566 | p.translate(offset, 0); |
567 | p.rotate(45.0); |
568 | p.scale(2.0, 2.0); |
569 | p.translate(100, 200); |
570 | |
571 | QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit." ); |
572 | text.setTextFormat(Qt::PlainText); |
573 | |
574 | p.drawStaticText(QPointF(11, 12 - QFontMetricsF(p.font()).ascent()), text); |
575 | } |
576 | |
577 | #if defined(DEBUG_SAVE_IMAGE) |
578 | imageDrawText.save("rotatedScaledAndPainter_imageDrawText.png" ); |
579 | imageDrawStaticText.save("rotatedScaledAndPainter_imageDrawStaticText.png" ); |
580 | #endif |
581 | |
582 | QVERIFY(imageDrawText.toImage() != m_whiteSquare); |
583 | |
584 | if (!supportsTransformations()) |
585 | QEXPECT_FAIL("" , "Graphics system does not support transformed text on this platform" , Abort); |
586 | QCOMPARE(imageDrawStaticText, imageDrawText); |
587 | } |
588 | #endif |
589 | |
590 | void tst_QStaticText::transformationChanged() |
591 | { |
592 | QPixmap imageDrawText(1000, 1000); |
593 | imageDrawText.fill(fillColor: Qt::white); |
594 | { |
595 | QPainter p(&imageDrawText); |
596 | p.rotate(a: 33.0); |
597 | p.scale(sx: 0.5, sy: 0.7); |
598 | |
599 | p.drawText(r: QRectF(0, 0, 1000, 1000), flags: 0, text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit." ); |
600 | |
601 | p.scale(sx: 2.0, sy: 2.5); |
602 | p.drawText(r: QRectF(0, 0, 1000, 1000), flags: 0, text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit." ); |
603 | } |
604 | |
605 | QPixmap imageDrawStaticText(1000, 1000); |
606 | imageDrawStaticText.fill(fillColor: Qt::white); |
607 | { |
608 | QPainter p(&imageDrawStaticText); |
609 | p.rotate(a: 33.0); |
610 | p.scale(sx: 0.5, sy: 0.7); |
611 | |
612 | QStaticText text("Lorem ipsum dolor sit amet, consectetur adipiscing elit." ); |
613 | text.setTextFormat(Qt::PlainText); |
614 | |
615 | p.drawStaticText(topLeftPosition: QPointF(0, 0), staticText: text); |
616 | |
617 | p.scale(sx: 2.0, sy: 2.5); |
618 | p.drawStaticText(topLeftPosition: QPointF(0, 0), staticText: text); |
619 | } |
620 | |
621 | #if defined(DEBUG_SAVE_IMAGE) |
622 | imageDrawText.save("transformationChanged_imageDrawText.png" ); |
623 | imageDrawStaticText.save("transformationChanged_imageDrawStaticText.png" ); |
624 | #endif |
625 | |
626 | QVERIFY(imageDrawText.toImage() != m_whiteSquare); |
627 | |
628 | #ifdef Q_OS_ANDROID |
629 | QEXPECT_FAIL("" , "QTBUG-69220" , Continue); |
630 | #endif |
631 | if (!supportsTransformations()) |
632 | QEXPECT_FAIL("" , "Graphics system does not support transformed text on this platform" , Abort); |
633 | QCOMPARE(imageDrawStaticText, imageDrawText); |
634 | } |
635 | |
636 | void tst_QStaticText::plainTextVsRichText() |
637 | { |
638 | QPixmap imagePlainText(1000, 1000); |
639 | imagePlainText.fill(fillColor: Qt::white); |
640 | { |
641 | QPainter p(&imagePlainText); |
642 | |
643 | QStaticText staticText; |
644 | staticText.setText("FOObar" ); |
645 | staticText.setTextFormat(Qt::PlainText); |
646 | |
647 | p.drawStaticText(x: 10, y: 10, staticText); |
648 | } |
649 | |
650 | QPixmap imageRichText(1000, 1000); |
651 | imageRichText.fill(fillColor: Qt::white); |
652 | { |
653 | QPainter p(&imageRichText); |
654 | |
655 | QStaticText staticText; |
656 | staticText.setText("<html><body>FOObar</body></html>" ); |
657 | staticText.setTextFormat(Qt::RichText); |
658 | |
659 | p.drawStaticText(x: 10, y: 10, staticText); |
660 | } |
661 | |
662 | #if defined(DEBUG_SAVE_IMAGE) |
663 | imagePlainText.save("plainTextVsRichText_imagePlainText.png" ); |
664 | imageRichText.save("plainTextVsRichText_imageRichText.png" ); |
665 | #endif |
666 | |
667 | QVERIFY(imagePlainText.toImage() != m_whiteSquare); |
668 | QCOMPARE(imagePlainText, imageRichText); |
669 | } |
670 | |
671 | static bool checkPixels(const QImage &image, |
672 | Qt::GlobalColor expectedColor1, Qt::GlobalColor expectedColor2, |
673 | QByteArray *errorMessage) |
674 | { |
675 | const QRgb expectedRgb1 = QColor(expectedColor1).rgba(); |
676 | const QRgb expectedRgb2 = QColor(expectedColor2).rgba(); |
677 | |
678 | for (int x = 0, w = image.width(); x < w; ++x) { |
679 | for (int y = 0, h = image.height(); y < h; ++y) { |
680 | const QRgb pixel = image.pixel(x, y); |
681 | if (pixel != expectedRgb1 && pixel != expectedRgb2) { |
682 | QString message; |
683 | QDebug(&message) << "Color mismatch in image" << image |
684 | << "at" << x << ',' << y << ':' << Qt::showbase << Qt::hex << pixel |
685 | << "(expected: " << expectedRgb1 << ',' << expectedRgb2 << ')'; |
686 | *errorMessage = message.toLocal8Bit(); |
687 | return false; |
688 | } |
689 | } |
690 | } |
691 | return true; |
692 | } |
693 | |
694 | void tst_QStaticText::setPenPlainText_data() |
695 | { |
696 | QTest::addColumn<QImage::Format>(name: "format" ); |
697 | |
698 | QTest::newRow(dataTag: "argb32pm" ) << QImage::Format_ARGB32_Premultiplied; |
699 | QTest::newRow(dataTag: "rgb32" ) << QImage::Format_RGB32; |
700 | QTest::newRow(dataTag: "rgba8888pm" ) << QImage::Format_RGBA8888_Premultiplied; |
701 | QTest::newRow(dataTag: "rgbx8888" ) << QImage::Format_RGBX8888; |
702 | } |
703 | |
704 | void tst_QStaticText::setPenPlainText() |
705 | { |
706 | QFETCH(QImage::Format, format); |
707 | |
708 | QFont font = QGuiApplication::font(); |
709 | font.setStyleStrategy(QFont::NoAntialias); |
710 | |
711 | QFontMetricsF fm(font); |
712 | QImage image(qCeil(v: fm.horizontalAdvance(string: "XXXXX" )), qCeil(v: fm.height()), format); |
713 | image.fill(color: Qt::white); |
714 | { |
715 | QPainter p(&image); |
716 | p.setFont(font); |
717 | p.setPen(Qt::yellow); |
718 | |
719 | QStaticText staticText("XXXXX" ); |
720 | staticText.setTextFormat(Qt::PlainText); |
721 | p.drawStaticText(x: 0, y: 0, staticText); |
722 | } |
723 | |
724 | QByteArray errorMessage; |
725 | QVERIFY2(checkPixels(image, Qt::yellow, Qt::white, &errorMessage), |
726 | errorMessage.constData()); |
727 | } |
728 | |
729 | void tst_QStaticText::setPenRichText() |
730 | { |
731 | QFont font = QGuiApplication::font(); |
732 | font.setStyleStrategy(QFont::NoAntialias); |
733 | |
734 | QFontMetricsF fm(font); |
735 | QPixmap image(qCeil(v: fm.horizontalAdvance(string: "XXXXX" )), qCeil(v: fm.height())); |
736 | image.fill(fillColor: Qt::white); |
737 | { |
738 | QPainter p(&image); |
739 | p.setFont(font); |
740 | p.setPen(Qt::green); |
741 | |
742 | QStaticText staticText; |
743 | staticText.setText("<html><body>XXXXX</body></html>" ); |
744 | staticText.setTextFormat(Qt::RichText); |
745 | p.drawStaticText(x: 0, y: 0, staticText); |
746 | } |
747 | |
748 | QByteArray errorMessage; |
749 | QVERIFY2(checkPixels(image.toImage(), Qt::green, Qt::white, &errorMessage), |
750 | errorMessage.constData()); |
751 | } |
752 | |
753 | void tst_QStaticText::richTextOverridesPen() |
754 | { |
755 | QFont font = QGuiApplication::font(); |
756 | font.setStyleStrategy(QFont::NoAntialias); |
757 | |
758 | QFontMetricsF fm(font); |
759 | QPixmap image(qCeil(v: fm.horizontalAdvance(string: "XXXXX" )), qCeil(v: fm.height())); |
760 | image.fill(fillColor: Qt::white); |
761 | { |
762 | QPainter p(&image); |
763 | p.setFont(font); |
764 | p.setPen(Qt::green); |
765 | |
766 | QStaticText staticText; |
767 | staticText.setText("<html><body><font color=\"#ff0000\">XXXXX</font></body></html>" ); |
768 | staticText.setTextFormat(Qt::RichText); |
769 | p.drawStaticText(x: 0, y: 0, staticText); |
770 | } |
771 | |
772 | QByteArray errorMessage; |
773 | QVERIFY2(checkPixels(image.toImage(), Qt::red, Qt::white, &errorMessage), |
774 | errorMessage.constData()); |
775 | } |
776 | |
777 | void tst_QStaticText::drawStruckOutText() |
778 | { |
779 | QPixmap imageDrawText(1000, 1000); |
780 | QPixmap imageDrawStaticText(1000, 1000); |
781 | |
782 | imageDrawText.fill(fillColor: Qt::white); |
783 | imageDrawStaticText.fill(fillColor: Qt::white); |
784 | |
785 | QString s = QString::fromLatin1(str: "Foobar" ); |
786 | |
787 | QFont font; |
788 | font.setStrikeOut(true); |
789 | font.setStyleStrategy(QFont::ForceIntegerMetrics); |
790 | |
791 | { |
792 | QPainter p(&imageDrawText); |
793 | p.setFont(font); |
794 | p.drawText(p: QPointF(50, 50), s); |
795 | } |
796 | |
797 | { |
798 | QPainter p(&imageDrawStaticText); |
799 | QStaticText text = QStaticText(s); |
800 | p.setFont(font); |
801 | p.drawStaticText(topLeftPosition: QPointF(50, 50 - QFontMetricsF(p.font()).ascent()), staticText: text); |
802 | } |
803 | |
804 | #if defined(DEBUG_SAVE_IMAGE) |
805 | imageDrawText.save("drawStruckOutText_imageDrawText.png" ); |
806 | imageDrawStaticText.save("drawStruckOutText_imageDrawStaticText.png" ); |
807 | #endif |
808 | |
809 | QVERIFY(imageDrawText.toImage() != m_whiteSquare); |
810 | QCOMPARE(imageDrawText, imageDrawStaticText); |
811 | } |
812 | |
813 | void tst_QStaticText::drawOverlinedText() |
814 | { |
815 | QPixmap imageDrawText(1000, 1000); |
816 | QPixmap imageDrawStaticText(1000, 1000); |
817 | |
818 | imageDrawText.fill(fillColor: Qt::white); |
819 | imageDrawStaticText.fill(fillColor: Qt::white); |
820 | |
821 | QString s = QString::fromLatin1(str: "Foobar" ); |
822 | |
823 | QFont font; |
824 | font.setOverline(true); |
825 | font.setStyleStrategy(QFont::ForceIntegerMetrics); |
826 | |
827 | { |
828 | QPainter p(&imageDrawText); |
829 | p.setFont(font); |
830 | p.drawText(p: QPointF(50, 50), s); |
831 | } |
832 | |
833 | { |
834 | QPainter p(&imageDrawStaticText); |
835 | QStaticText text = QStaticText(s); |
836 | p.setFont(font); |
837 | p.drawStaticText(topLeftPosition: QPointF(50, 50 - QFontMetricsF(p.font()).ascent()), staticText: text); |
838 | } |
839 | |
840 | #if defined(DEBUG_SAVE_IMAGE) |
841 | imageDrawText.save("drawOverlinedText_imageDrawText.png" ); |
842 | imageDrawStaticText.save("drawOverlinedText_imageDrawStaticText.png" ); |
843 | #endif |
844 | |
845 | QVERIFY(imageDrawText.toImage() != m_whiteSquare); |
846 | QCOMPARE(imageDrawText, imageDrawStaticText); |
847 | } |
848 | |
849 | void tst_QStaticText::drawUnderlinedText() |
850 | { |
851 | QPixmap imageDrawText(1000, 1000); |
852 | QPixmap imageDrawStaticText(1000, 1000); |
853 | |
854 | imageDrawText.fill(fillColor: Qt::white); |
855 | imageDrawStaticText.fill(fillColor: Qt::white); |
856 | |
857 | QString s = QString::fromLatin1(str: "Foobar" ); |
858 | |
859 | QFont font; |
860 | font.setUnderline(true); |
861 | font.setStyleStrategy(QFont::ForceIntegerMetrics); |
862 | |
863 | { |
864 | QPainter p(&imageDrawText); |
865 | p.setFont(font); |
866 | p.drawText(p: QPointF(50, 50), s); |
867 | } |
868 | |
869 | { |
870 | QPainter p(&imageDrawStaticText); |
871 | QStaticText text = QStaticText(s); |
872 | p.setFont(font); |
873 | p.drawStaticText(topLeftPosition: QPointF(50, 50 - QFontMetricsF(p.font()).ascent()), staticText: text); |
874 | } |
875 | |
876 | #if defined(DEBUG_SAVE_IMAGE) |
877 | imageDrawText.save("drawUnderlinedText_imageDrawText.png" ); |
878 | imageDrawStaticText.save("drawUnderlinedText_imageDrawStaticText.png" ); |
879 | #endif |
880 | |
881 | QCOMPARE(imageDrawText, imageDrawStaticText); |
882 | } |
883 | |
884 | void tst_QStaticText::unprintableCharacter_qtbug12614() |
885 | { |
886 | QString s(QChar(0x200B)); // U+200B, ZERO WIDTH SPACE |
887 | |
888 | QStaticText staticText(s); |
889 | |
890 | QVERIFY(staticText.size().isValid()); // Force layout. Should not crash. |
891 | } |
892 | |
893 | #ifdef QT_BUILD_INTERNAL |
894 | void tst_QStaticText::underlinedColor_qtbug20159() |
895 | { |
896 | QString multiScriptText; |
897 | multiScriptText += QChar(0x0410); // Cyrillic 'A' |
898 | multiScriptText += QLatin1Char('A'); |
899 | |
900 | QStaticText staticText(multiScriptText); |
901 | |
902 | QFont font; |
903 | font.setUnderline(true); |
904 | |
905 | staticText.prepare(matrix: QTransform(), font); |
906 | |
907 | QStaticTextPrivate *d = QStaticTextPrivate::get(q: &staticText); |
908 | QCOMPARE(d->itemCount, 2); |
909 | |
910 | // The pen should not be marked as dirty when drawing the underline |
911 | QVERIFY(!d->items[0].color.isValid()); |
912 | QVERIFY(!d->items[1].color.isValid()); |
913 | } |
914 | |
915 | void tst_QStaticText::textDocumentColor() |
916 | { |
917 | QStaticText staticText("A<font color=\"red\">B</font>" ); |
918 | staticText.setTextFormat(Qt::RichText); |
919 | staticText.prepare(); |
920 | |
921 | QStaticTextPrivate *d = QStaticTextPrivate::get(q: &staticText); |
922 | QCOMPARE(d->itemCount, 2); |
923 | |
924 | // The pen should not be marked as dirty when drawing the underline |
925 | QVERIFY(!d->items[0].color.isValid()); |
926 | QVERIFY(d->items[1].color.isValid()); |
927 | |
928 | QCOMPARE(d->items[1].color, QColor(Qt::red)); |
929 | } |
930 | #endif |
931 | |
932 | class TestPaintEngine: public QPaintEngine |
933 | { |
934 | public: |
935 | void drawTextItem(const QPointF &p, const QTextItem &) override |
936 | { |
937 | differentVerticalPositions.insert(value: qRound(d: p.y())); |
938 | } |
939 | |
940 | void updateState(const QPaintEngineState &) override {} |
941 | |
942 | void drawPolygon(const QPointF *, int , PolygonDrawMode ) override {} |
943 | |
944 | bool begin(QPaintDevice *) override { return true; } |
945 | bool end() override { return true; } |
946 | void drawPixmap(const QRectF &, const QPixmap &, const QRectF &) override {} |
947 | Type type() const override |
948 | { |
949 | return User; |
950 | } |
951 | |
952 | QSet<int> differentVerticalPositions; |
953 | }; |
954 | |
955 | class TestPixmap: public QPixmap |
956 | { |
957 | public: |
958 | TestPixmap(int w, int h) : QPixmap(w, h), testPaintEngine(new TestPaintEngine) {} |
959 | ~TestPixmap() { delete testPaintEngine; } |
960 | |
961 | QPaintEngine *paintEngine() const |
962 | { |
963 | return testPaintEngine; |
964 | } |
965 | |
966 | TestPaintEngine *testPaintEngine; |
967 | }; |
968 | |
969 | void tst_QStaticText::multiLine() |
970 | { |
971 | TestPixmap pixmap(100, 100); |
972 | |
973 | TestPaintEngine *paintEngine = pixmap.testPaintEngine; |
974 | |
975 | { |
976 | QPainter p(&pixmap); |
977 | QStaticText text; |
978 | text.setText(QLatin1String("line 1" ) + QChar(QChar::LineSeparator) + QLatin1String("line 2" )); |
979 | p.drawStaticText(x: 0, y: 0, staticText: text); |
980 | } |
981 | |
982 | QCOMPARE(paintEngine->differentVerticalPositions.size(), 2); |
983 | } |
984 | |
985 | void tst_QStaticText::size_qtbug65836() |
986 | { |
987 | const QString text = QLatin1String("Lorem ipsum dolor sit amet, " |
988 | "consectetur adipiscing elit." ); |
989 | QFont font("Courier" ); |
990 | font.setPixelSize(15); |
991 | |
992 | { |
993 | QStaticText st1(text); |
994 | st1.setTextFormat(Qt::PlainText); |
995 | st1.prepare(matrix: QTransform(), font); |
996 | |
997 | QStaticText st2(text); |
998 | st2.setTextFormat(Qt::RichText); |
999 | QTextOption opt; |
1000 | opt.setWrapMode(QTextOption::NoWrap); |
1001 | st2.setTextOption(opt); |
1002 | st2.prepare(matrix: QTransform(), font); |
1003 | |
1004 | QCOMPARE(st1.size(), st2.size()); |
1005 | } |
1006 | |
1007 | { |
1008 | QStaticText st1(text); |
1009 | st1.setTextFormat(Qt::PlainText); |
1010 | st1.setTextWidth(10.0); |
1011 | st1.prepare(matrix: QTransform(), font); |
1012 | |
1013 | QStaticText st2(text); |
1014 | st2.setTextFormat(Qt::RichText); |
1015 | st2.setTextWidth(10.0); |
1016 | st2.prepare(matrix: QTransform(), font); |
1017 | |
1018 | QCOMPARE(st1.size(), st2.size()); |
1019 | } |
1020 | } |
1021 | |
1022 | QTEST_MAIN(tst_QStaticText) |
1023 | #include "tst_qstatictext.moc" |
1024 | |