1 /****************************************************************************
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
6 ** This file is part of the test suite of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
40 ****************************************************************************/
42 #include <QtTest/QtTest>
44 #include <qglyphrun.h>
46 #include <qtextlayout.h>
47 #include <qfontdatabase.h>
49 // #define DEBUG_SAVE_IMAGE
51 class tst_QGlyphRun: public QObject
55 #if !defined(QT_NO_RAWFONT)
59 void cleanupTestCase();
61 void constructionAndDestruction();
62 void copyConstructor();
64 void equalsOperator_data();
65 void equalsOperator();
67 void textLayoutGlyphIndexes();
68 void drawExistingGlyphs();
69 void drawNonExistentGlyphs();
70 void drawMultiScriptText1();
71 void drawMultiScriptText2();
72 void drawStruckOutText();
73 void drawOverlinedText();
74 void drawUnderlinedText();
75 void drawRightToLeft();
78 void setRawDataAndGetAsVector();
85 #endif // QT_NO_RAWFONT
89 #if !defined(QT_NO_RAWFONT)
91 Q_DECLARE_METATYPE(QGlyphRun);
93 void tst_QGlyphRun::initTestCase()
95 m_testFont_ok = false;
97 m_testFontId = QFontDatabase::addApplicationFont(SRCDIR "test.ttf");
98 QVERIFY(m_testFontId >= 0);
100 m_testFont = QFont("QtsSpecialTestFont");
102 QCOMPARE(QFontInfo(m_testFont).family(), QString::fromLatin1("QtsSpecialTestFont"));
104 m_testFont_ok = true;
107 void tst_QGlyphRun::init()
110 QSKIP("Test font is not working correctly");
113 void tst_QGlyphRun::cleanupTestCase()
115 QFontDatabase::removeApplicationFont(m_testFontId);
118 void tst_QGlyphRun::constructionAndDestruction()
120 QGlyphRun glyphIndexes;
123 static QGlyphRun make_dummy_indexes()
127 QVector<quint32> glyphIndexes;
128 QVector<QPointF> positions;
130 font.setPointSize(18);
132 glyphIndexes.append(1);
133 glyphIndexes.append(2);
134 glyphIndexes.append(3);
136 positions.append(QPointF(1, 2));
137 positions.append(QPointF(3, 4));
138 positions.append(QPointF(5, 6));
140 glyphs.setRawFont(QRawFont::fromFont(font));
141 glyphs.setGlyphIndexes(glyphIndexes);
142 glyphs.setPositions(positions);
147 void tst_QGlyphRun::copyConstructor()
152 QVector<quint32> glyphIndexes;
153 QVector<QPointF> positions;
155 font.setPointSize(18);
157 glyphIndexes.append(1);
158 glyphIndexes.append(2);
159 glyphIndexes.append(3);
161 positions.append(QPointF(1, 2));
162 positions.append(QPointF(3, 4));
163 positions.append(QPointF(5, 6));
165 glyphs.setRawFont(QRawFont::fromFont(font));
166 glyphs.setGlyphIndexes(glyphIndexes);
167 glyphs.setPositions(positions);
170 QGlyphRun otherGlyphs(glyphs);
171 QCOMPARE(otherGlyphs.rawFont(), glyphs.rawFont());
172 QCOMPARE(glyphs.glyphIndexes(), otherGlyphs.glyphIndexes());
173 QCOMPARE(glyphs.positions(), otherGlyphs.positions());
176 void tst_QGlyphRun::assignment()
178 QGlyphRun glyphs(make_dummy_indexes());
180 QGlyphRun otherGlyphs = glyphs;
181 QCOMPARE(otherGlyphs.rawFont(), glyphs.rawFont());
182 QCOMPARE(glyphs.glyphIndexes(), otherGlyphs.glyphIndexes());
183 QCOMPARE(glyphs.positions(), otherGlyphs.positions());
186 void tst_QGlyphRun::equalsOperator_data()
188 QTest::addColumn<QGlyphRun>("one");
189 QTest::addColumn<QGlyphRun>("two");
190 QTest::addColumn<bool>("equals");
192 QGlyphRun one(make_dummy_indexes());
193 QGlyphRun two(make_dummy_indexes());
195 QTest::newRow("Identical") << one << two << true;
198 QGlyphRun busted(two);
200 QVector<QPointF> positions = busted.positions();
201 positions[2] += QPointF(1, 1);
202 busted.setPositions(positions);
205 QTest::newRow("Different positions") << one << busted << false;
209 QGlyphRun busted(two);
212 font.setPixelSize(busted.rawFont().pixelSize() * 2);
213 busted.setRawFont(QRawFont::fromFont(font));
215 QTest::newRow("Different fonts") << one << busted << false;
219 QGlyphRun busted(two);
221 QVector<quint32> glyphIndexes = busted.glyphIndexes();
222 glyphIndexes[2] += 1;
223 busted.setGlyphIndexes(glyphIndexes);
225 QTest::newRow("Different glyph indexes") << one << busted << false;
230 void tst_QGlyphRun::equalsOperator()
232 QFETCH(QGlyphRun, one);
233 QFETCH(QGlyphRun, two);
234 QFETCH(bool, equals);
236 QCOMPARE(one == two, equals);
237 QCOMPARE(one != two, !equals);
240 void tst_QGlyphRun::isEmpty()
243 QVERIFY(glyphs.isEmpty());
245 glyphs.setGlyphIndexes(QVector<quint32>() << 1 << 2 << 3);
246 QVERIFY(!glyphs.isEmpty());
249 QVERIFY(glyphs.isEmpty());
251 QVector<quint32> glyphIndexes = QVector<quint32>() << 1 << 2 << 3;
252 QVector<QPointF> positions = QVector<QPointF>() << QPointF(0, 0) << QPointF(0, 0) << QPointF(0, 0);
253 glyphs.setRawData(glyphIndexes.constData(), positions.constData(), glyphIndexes.size());
254 QVERIFY(!glyphs.isEmpty());
257 void tst_QGlyphRun::textLayoutGlyphIndexes()
260 s.append(QLatin1Char('A'));
261 s.append(QChar(0xe000));
263 QTextLayout layout(s);
264 layout.setFont(m_testFont);
265 layout.setCacheEnabled(true);
266 layout.beginLayout();
270 QList<QGlyphRun> listOfGlyphs = layout.glyphRuns();
272 QCOMPARE(listOfGlyphs.size(), 1);
274 QGlyphRun glyphs = listOfGlyphs.at(0);
276 QCOMPARE(glyphs.glyphIndexes().size(), 2);
277 QCOMPARE(glyphs.glyphIndexes().at(0), quint32(2));
278 QCOMPARE(glyphs.glyphIndexes().at(1), quint32(1));
281 void tst_QGlyphRun::drawExistingGlyphs()
283 QPixmap textLayoutDraw(1000, 1000);
284 QPixmap drawGlyphs(1000, 1000);
286 textLayoutDraw.fill(Qt::white);
287 drawGlyphs.fill(Qt::white);
290 s.append(QLatin1Char('A'));
291 s.append(QChar(0xe000));
293 QTextLayout layout(s);
294 layout.setFont(m_testFont);
295 layout.setCacheEnabled(true);
296 layout.beginLayout();
301 QPainter p(&textLayoutDraw);
302 layout.draw(&p, QPointF(50, 50));
305 QGlyphRun glyphs = layout.glyphRuns().size() > 0
306 ? layout.glyphRuns().at(0)
310 QPainter p(&drawGlyphs);
311 p.drawGlyphRun(QPointF(50, 50), glyphs);
314 #if defined(DEBUG_SAVE_IMAGE)
315 textLayoutDraw.save("drawExistingGlyphs_textLayoutDraw.png");
316 drawGlyphs.save("drawExistingGlyphs_drawGlyphIndexes.png");
319 QCOMPARE(textLayoutDraw, drawGlyphs);
322 void tst_QGlyphRun::setRawData()
325 glyphRun.setRawFont(QRawFont::fromFont(m_testFont));
326 glyphRun.setGlyphIndexes(QVector<quint32>() << 2 << 2 << 2);
327 glyphRun.setPositions(QVector<QPointF>() << QPointF(2, 3) << QPointF(20, 3) << QPointF(10, 20));
329 QPixmap baseline(100, 50);
330 baseline.fill(Qt::white);
332 QPainter p(&baseline);
333 p.drawGlyphRun(QPointF(3, 2), glyphRun);
336 QGlyphRun baselineCopied = glyphRun;
338 quint32 glyphIndexArray[3] = { 2, 2, 2 };
339 QPointF glyphPositionArray[3] = { QPointF(2, 3), QPointF(20, 3), QPointF(10, 20) };
341 glyphRun.setRawData(glyphIndexArray, glyphPositionArray, 3);
343 QPixmap rawDataGlyphs(100, 50);
344 rawDataGlyphs.fill(Qt::white);
346 QPainter p(&rawDataGlyphs);
347 p.drawGlyphRun(QPointF(3, 2), glyphRun);
350 quint32 otherGlyphIndexArray[1] = { 2 };
351 QPointF otherGlyphPositionArray[1] = { QPointF(2, 3) };
353 glyphRun.setRawData(otherGlyphIndexArray, otherGlyphPositionArray, 1);
355 QPixmap baselineCopiedPixmap(100, 50);
356 baselineCopiedPixmap.fill(Qt::white);
358 QPainter p(&baselineCopiedPixmap);
359 p.drawGlyphRun(QPointF(3, 2), baselineCopied);
362 #if defined(DEBUG_SAVE_IMAGE)
363 baseline.save("setRawData_baseline.png");
364 rawDataGlyphs.save("setRawData_rawDataGlyphs.png");
365 baselineCopiedPixmap.save("setRawData_baselineCopiedPixmap.png");
368 QCOMPARE(rawDataGlyphs, baseline);
369 QCOMPARE(baselineCopiedPixmap, baseline);
372 void tst_QGlyphRun::setRawDataAndGetAsVector()
374 QVector<quint32> glyphIndexArray;
375 glyphIndexArray << 3 << 2 << 1 << 4;
377 QVector<QPointF> glyphPositionArray;
378 glyphPositionArray << QPointF(1, 2) << QPointF(3, 4) << QPointF(5, 6) << QPointF(7, 8);
381 glyphRun.setRawData(glyphIndexArray.constData(), glyphPositionArray.constData(), 4);
383 QVector<quint32> glyphIndexes = glyphRun.glyphIndexes();
384 QVector<QPointF> glyphPositions = glyphRun.positions();
386 QCOMPARE(glyphIndexes.size(), 4);
387 QCOMPARE(glyphPositions.size(), 4);
389 QCOMPARE(glyphIndexes, glyphIndexArray);
390 QCOMPARE(glyphPositions, glyphPositionArray);
392 QGlyphRun otherGlyphRun;
393 otherGlyphRun.setGlyphIndexes(glyphIndexArray);
394 otherGlyphRun.setPositions(glyphPositionArray);
396 QCOMPARE(glyphRun, otherGlyphRun);
399 void tst_QGlyphRun::drawNonExistentGlyphs()
401 QVector<quint32> glyphIndexes;
402 glyphIndexes.append(3);
404 QVector<QPointF> glyphPositions;
405 glyphPositions.append(QPointF(0, 0));
408 glyphs.setGlyphIndexes(glyphIndexes);
409 glyphs.setPositions(glyphPositions);
410 glyphs.setRawFont(QRawFont::fromFont(m_testFont));
412 QPixmap image(1000, 1000);
413 image.fill(Qt::white);
415 QPixmap imageBefore = image;
418 p.drawGlyphRun(QPointF(50, 50), glyphs);
421 #if defined(DEBUG_SAVE_IMAGE)
422 image.save("drawNonExistentGlyphs.png");
425 QCOMPARE(image, imageBefore); // Should be unchanged
428 void tst_QGlyphRun::drawMultiScriptText1()
431 text += QChar(0x03D0); // Greek, beta
433 QTextLayout textLayout(text);
434 textLayout.setCacheEnabled(true);
435 textLayout.beginLayout();
436 textLayout.createLine();
437 textLayout.endLayout();
439 QPixmap textLayoutDraw(1000, 1000);
440 textLayoutDraw.fill(Qt::white);
442 QPixmap drawGlyphs(1000, 1000);
443 drawGlyphs.fill(Qt::white);
445 QList<QGlyphRun> glyphsList = textLayout.glyphRuns();
446 QCOMPARE(glyphsList.size(), 1);
449 QPainter p(&textLayoutDraw);
450 textLayout.draw(&p, QPointF(50, 50));
454 QPainter p(&drawGlyphs);
455 foreach (QGlyphRun glyphs, glyphsList)
456 p.drawGlyphRun(QPointF(50, 50), glyphs);
459 #if defined(DEBUG_SAVE_IMAGE)
460 textLayoutDraw.save("drawMultiScriptText1_textLayoutDraw.png");
461 drawGlyphs.save("drawMultiScriptText1_drawGlyphIndexes.png");
464 QCOMPARE(drawGlyphs, textLayoutDraw);
468 void tst_QGlyphRun::drawMultiScriptText2()
471 text += QChar(0x0621); // Arabic, Hamza
472 text += QChar(0x03D0); // Greek, beta
474 QTextLayout textLayout(text);
475 textLayout.setCacheEnabled(true);
476 textLayout.beginLayout();
477 textLayout.createLine();
478 textLayout.endLayout();
480 QPixmap textLayoutDraw(1000, 1000);
481 textLayoutDraw.fill(Qt::white);
483 QPixmap drawGlyphs(1000, 1000);
484 drawGlyphs.fill(Qt::white);
486 QList<QGlyphRun> glyphsList = textLayout.glyphRuns();
487 QCOMPARE(glyphsList.size(), 2);
490 QPainter p(&textLayoutDraw);
491 textLayout.draw(&p, QPointF(50, 50));
495 QPainter p(&drawGlyphs);
496 foreach (QGlyphRun glyphs, glyphsList)
497 p.drawGlyphRun(QPointF(50, 50), glyphs);
500 #if defined(DEBUG_SAVE_IMAGE)
501 textLayoutDraw.save("drawMultiScriptText2_textLayoutDraw.png");
502 drawGlyphs.save("drawMultiScriptText2_drawGlyphIndexes.png");
505 QCOMPARE(drawGlyphs, textLayoutDraw);
508 void tst_QGlyphRun::detach()
512 glyphs.setGlyphIndexes(QVector<quint32>() << 1 << 2 << 3);
514 QGlyphRun otherGlyphs;
515 otherGlyphs = glyphs;
517 QCOMPARE(otherGlyphs.glyphIndexes(), glyphs.glyphIndexes());
519 otherGlyphs.setGlyphIndexes(QVector<quint32>() << 4 << 5 << 6);
521 QCOMPARE(otherGlyphs.glyphIndexes(), QVector<quint32>() << 4 << 5 << 6);
522 QCOMPARE(glyphs.glyphIndexes(), QVector<quint32>() << 1 << 2 << 3);
525 void tst_QGlyphRun::drawStruckOutText()
527 QPixmap textLayoutDraw(1000, 1000);
528 QPixmap drawGlyphs(1000, 1000);
530 textLayoutDraw.fill(Qt::white);
531 drawGlyphs.fill(Qt::white);
533 QString s = QString::fromLatin1("Foobar");
536 font.setStrikeOut(true);
538 QTextLayout layout(s);
539 layout.setFont(font);
540 layout.setCacheEnabled(true);
541 layout.beginLayout();
546 QPainter p(&textLayoutDraw);
547 layout.draw(&p, QPointF(50, 50));
550 QGlyphRun glyphs = layout.glyphRuns().size() > 0
551 ? layout.glyphRuns().at(0)
555 QPainter p(&drawGlyphs);
556 p.drawGlyphRun(QPointF(50, 50), glyphs);
559 #if defined(DEBUG_SAVE_IMAGE)
560 textLayoutDraw.save("drawStruckOutText_textLayoutDraw.png");
561 drawGlyphs.save("drawStruckOutText_drawGlyphIndexes.png");
564 QCOMPARE(textLayoutDraw, drawGlyphs);
567 void tst_QGlyphRun::drawOverlinedText()
569 QPixmap textLayoutDraw(1000, 1000);
570 QPixmap drawGlyphs(1000, 1000);
572 textLayoutDraw.fill(Qt::white);
573 drawGlyphs.fill(Qt::white);
575 QString s = QString::fromLatin1("Foobar");
578 font.setOverline(true);
580 QTextLayout layout(s);
581 layout.setFont(font);
582 layout.setCacheEnabled(true);
583 layout.beginLayout();
588 QPainter p(&textLayoutDraw);
589 layout.draw(&p, QPointF(50, 50));
592 QGlyphRun glyphs = layout.glyphRuns().size() > 0
593 ? layout.glyphRuns().at(0)
597 QPainter p(&drawGlyphs);
598 p.drawGlyphRun(QPointF(50, 50), glyphs);
601 #if defined(DEBUG_SAVE_IMAGE)
602 textLayoutDraw.save("drawOverlineText_textLayoutDraw.png");
603 drawGlyphs.save("drawOverlineText_drawGlyphIndexes.png");
606 QCOMPARE(textLayoutDraw, drawGlyphs);
609 void tst_QGlyphRun::drawUnderlinedText()
611 QPixmap textLayoutDraw(1000, 1000);
612 QPixmap drawGlyphs(1000, 1000);
614 textLayoutDraw.fill(Qt::white);
615 drawGlyphs.fill(Qt::white);
617 QString s = QString::fromLatin1("Foobar");
620 font.setUnderline(true);
622 QTextLayout layout(s);
623 layout.setFont(font);
624 layout.setCacheEnabled(true);
625 layout.beginLayout();
630 QPainter p(&textLayoutDraw);
631 layout.draw(&p, QPointF(50, 50));
634 QGlyphRun glyphs = layout.glyphRuns().size() > 0
635 ? layout.glyphRuns().at(0)
639 QPainter p(&drawGlyphs);
640 p.drawGlyphRun(QPointF(50, 50), glyphs);
643 #if defined(DEBUG_SAVE_IMAGE)
644 textLayoutDraw.save("drawUnderlineText_textLayoutDraw.png");
645 drawGlyphs.save("drawUnderlineText_drawGlyphIndexes.png");
648 QCOMPARE(textLayoutDraw, drawGlyphs);
651 void tst_QGlyphRun::drawRightToLeft()
654 s.append(QChar(1575));
655 s.append(QChar(1578));
657 QPixmap textLayoutDraw(1000, 1000);
658 QPixmap drawGlyphs(1000, 1000);
660 textLayoutDraw.fill(Qt::white);
661 drawGlyphs.fill(Qt::white);
664 font.setUnderline(true);
666 QTextLayout layout(s);
667 layout.setFont(font);
668 layout.setCacheEnabled(true);
669 layout.beginLayout();
674 QPainter p(&textLayoutDraw);
675 layout.draw(&p, QPointF(50, 50));
678 QGlyphRun glyphs = layout.glyphRuns().size() > 0
679 ? layout.glyphRuns().at(0)
683 QPainter p(&drawGlyphs);
684 p.drawGlyphRun(QPointF(50, 50), glyphs);
687 #if defined(DEBUG_SAVE_IMAGE)
688 textLayoutDraw.save("drawRightToLeft_textLayoutDraw.png");
689 drawGlyphs.save("drawRightToLeft_drawGlyphIndexes.png");
692 QCOMPARE(textLayoutDraw, drawGlyphs);
696 void tst_QGlyphRun::boundingRect()
698 QString s(QLatin1String("AbCdE"));
700 QRawFont rawFont(QRawFont::fromFont(QFont()));
701 QVERIFY(rawFont.isValid());
702 QVector<quint32> glyphIndexes = rawFont.glyphIndexesForString(s);
703 QVector<QPointF> positions = rawFont.advancesForGlyphIndexes(glyphIndexes);
704 QCOMPARE(glyphIndexes.size(), s.size());
705 QCOMPARE(positions.size(), glyphIndexes.size());
708 glyphs.setRawFont(rawFont);
709 glyphs.setGlyphIndexes(glyphIndexes);
710 glyphs.setPositions(positions);
712 QRectF boundingRect = glyphs.boundingRect();
715 glyphs.setRawFont(rawFont);
716 glyphs.setRawData(glyphIndexes.constData(), positions.constData(), glyphIndexes.size());
717 QCOMPARE(glyphs.boundingRect(), boundingRect);
719 boundingRect = QRectF(0, 0, 1, 1);
720 glyphs.setBoundingRect(boundingRect);
721 QCOMPARE(glyphs.boundingRect(), boundingRect);
724 #endif // QT_NO_RAWFONT
726 QTEST_MAIN(tst_QGlyphRun)
727 #include "tst_qglyphrun.moc"