1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the test suite of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include <QtTest/QSignalSpy>
43 #include <QTextDocument>
44 #include <QtQml/qqmlengine.h>
45 #include <QtQml/qqmlcomponent.h>
46 #include <QtQuick/private/qquicktext_p.h>
47 #include <private/qquicktext_p_p.h>
48 #include <private/qquickvaluetypes_p.h>
49 #include <QFontMetrics>
51 #include <QtQuick/QQuickView>
52 #include <private/qguiapplication_p.h>
54 #include <QtGui/QMouseEvent>
55 #include "../../shared/util.h"
56 #include "testhttpserver.h"
58 DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
60 #define SERVER_PORT 14459
61 #define SERVER_ADDR "http://127.0.0.1:14459"
63 Q_DECLARE_METATYPE(QQuickText::TextFormat)
66 extern void qt_setQtEnableTestFont(bool value);
69 class tst_qquicktext : public QQmlDataTest
80 void multilineElide_data();
81 void multilineElide();
82 void implicitElide_data();
86 void alignments_data();
90 void embeddedImages_data();
91 void embeddedImages();
96 // ### these tests may be trivial
97 void horizontalAlignment();
98 void horizontalAlignment_RightToLeft();
99 void verticalAlignment();
100 void hAlignImplicitWidth();
107 // QQuickFontValueType
112 void capitalization();
113 void letterSpacing();
116 void clickLink_data();
119 void implicitSize_data();
122 void implicitSizeBinding_data();
123 void implicitSizeBinding();
124 void geometryChanged();
126 void boundingRect_data();
130 void lineLaidOutRelayout();
132 void imgTagsBaseUrl_data();
133 void imgTagsBaseUrl();
134 void imgTagsAlign_data();
136 void imgTagsMultipleImages();
138 void imgTagsUpdates();
140 void fontSizeMode_data();
142 void fontSizeModeMultiline_data();
143 void fontSizeModeMultiline();
144 void multilengthStrings_data();
145 void multilengthStrings();
146 void fontFormatSizes_data();
147 void fontFormatSizes();
149 void baselineOffset_data();
150 void baselineOffset();
153 void htmlLists_data();
156 QStringList standard;
157 QStringList richText;
159 QStringList horizontalAlignmentmentStrings;
160 QStringList verticalAlignmentmentStrings;
162 QList<Qt::Alignment> verticalAlignmentments;
163 QList<Qt::Alignment> horizontalAlignmentments;
165 QStringList styleStrings;
166 QList<QQuickText::TextStyle> styles;
168 QStringList colorStrings;
172 QQuickView *createView(const QString &filename);
173 int numberOfNonWhitePixels(int fromX, int toX, const QImage &image);
176 tst_qquicktext::tst_qquicktext()
178 standard << "the quick brown fox jumped over the lazy dog"
179 << "the quick brown fox\n jumped over the lazy dog";
181 richText << "<i>the <b>quick</b> brown <a href=\\\"http://www.google.com\\\">fox</a> jumped over the <b>lazy</b> dog</i>"
182 << "<i>the <b>quick</b> brown <a href=\\\"http://www.google.com\\\">fox</a><br>jumped over the <b>lazy</b> dog</i>";
184 horizontalAlignmentmentStrings << "AlignLeft"
188 verticalAlignmentmentStrings << "AlignTop"
192 horizontalAlignmentments << Qt::AlignLeft
196 verticalAlignmentments << Qt::AlignTop
200 styleStrings << "Normal"
205 styles << QQuickText::Normal
206 << QQuickText::Outline
207 << QQuickText::Raised
208 << QQuickText::Sunken;
210 colorStrings << "aliceblue"
223 // need a different test to do alpha channel test
227 qt_setQtEnableTestFont(true);
230 QQuickView *tst_qquicktext::createView(const QString &filename)
232 QQuickView *window = new QQuickView(0);
234 window->setSource(QUrl::fromLocalFile(filename));
238 void tst_qquicktext::text()
241 QQmlComponent textComponent(&engine);
242 textComponent.setData("import QtQuick 2.0\nText { text: \"\" }", QUrl::fromLocalFile(""));
243 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
245 QVERIFY(textObject != 0);
246 QCOMPARE(textObject->text(), QString(""));
247 QVERIFY(textObject->width() == 0);
252 for (int i = 0; i < standard.size(); i++)
254 QString componentStr = "import QtQuick 2.0\nText { text: \"" + standard.at(i) + "\" }";
255 QQmlComponent textComponent(&engine);
256 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
258 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
260 QVERIFY(textObject != 0);
261 QCOMPARE(textObject->text(), standard.at(i));
262 QVERIFY(textObject->width() > 0);
267 for (int i = 0; i < richText.size(); i++)
269 QString componentStr = "import QtQuick 2.0\nText { text: \"" + richText.at(i) + "\" }";
270 QQmlComponent textComponent(&engine);
271 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
272 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
274 QVERIFY(textObject != 0);
275 QString expected = richText.at(i);
276 QCOMPARE(textObject->text(), expected.replace("\\\"", "\""));
277 QVERIFY(textObject->width() > 0);
283 void tst_qquicktext::width()
285 // uses Font metrics to find the width for standard and document to find the width for rich
287 QQmlComponent textComponent(&engine);
288 textComponent.setData("import QtQuick 2.0\nText { text: \"\" }", QUrl::fromLocalFile(""));
289 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
291 QVERIFY(textObject != 0);
292 QCOMPARE(textObject->width(), 0.);
297 bool requiresUnhintedMetrics = !qmlDisableDistanceField();
299 for (int i = 0; i < standard.size(); i++)
301 QVERIFY(!Qt::mightBeRichText(standard.at(i))); // self-test
304 qreal metricWidth = 0.0;
306 if (requiresUnhintedMetrics) {
307 QString s = standard.at(i);
308 s.replace(QLatin1Char('\n'), QChar::LineSeparator);
310 QTextLayout layout(s);
311 layout.setFlags(Qt::TextExpandTabs | Qt::TextShowMnemonic);
314 option.setUseDesignMetrics(true);
315 layout.setTextOption(option);
318 layout.beginLayout();
320 QTextLine line = layout.createLine();
327 metricWidth = layout.boundingRect().width();
330 metricWidth = fm.size(Qt::TextExpandTabs && Qt::TextShowMnemonic, standard.at(i)).width();
333 QString componentStr = "import QtQuick 2.0\nText { text: \"" + standard.at(i) + "\" }";
334 QQmlComponent textComponent(&engine);
335 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
336 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
338 QVERIFY(textObject != 0);
339 QVERIFY(textObject->boundingRect().width() > 0);
340 QCOMPARE(textObject->width(), qreal(metricWidth));
341 QVERIFY(textObject->textFormat() == QQuickText::AutoText); // setting text doesn't change format
346 for (int i = 0; i < richText.size(); i++)
348 QVERIFY(Qt::mightBeRichText(richText.at(i))); // self-test
350 QString componentStr = "import QtQuick 2.0\nText { text: \"" + richText.at(i) + "\"; textFormat: Text.RichText }";
351 QQmlComponent textComponent(&engine);
352 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
353 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
354 QVERIFY(textObject != 0);
356 QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject);
357 QVERIFY(textPrivate != 0);
358 QVERIFY(textPrivate->extra.isAllocated());
360 QTextDocument *doc = textPrivate->extra->doc;
363 QCOMPARE(int(textObject->width()), int(doc->idealWidth()));
364 QVERIFY(textObject->textFormat() == QQuickText::RichText);
370 void tst_qquicktext::wrap()
373 // for specified width and wrap set true
375 QQmlComponent textComponent(&engine);
376 textComponent.setData("import QtQuick 2.0\nText { text: \"Hello\"; wrapMode: Text.WordWrap; width: 300 }", QUrl::fromLocalFile(""));
377 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
378 textHeight = textObject->height();
380 QVERIFY(textObject != 0);
381 QVERIFY(textObject->wrapMode() == QQuickText::WordWrap);
382 QCOMPARE(textObject->width(), 300.);
387 for (int i = 0; i < standard.size(); i++)
389 QString componentStr = "import QtQuick 2.0\nText { wrapMode: Text.WordWrap; width: 30; text: \"" + standard.at(i) + "\" }";
390 QQmlComponent textComponent(&engine);
391 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
392 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
394 QVERIFY(textObject != 0);
395 QCOMPARE(textObject->width(), 30.);
396 QVERIFY(textObject->height() > textHeight);
398 int oldHeight = textObject->height();
399 textObject->setWidth(100);
400 QVERIFY(textObject->height() < oldHeight);
405 for (int i = 0; i < richText.size(); i++)
407 QString componentStr = "import QtQuick 2.0\nText { wrapMode: Text.WordWrap; width: 30; text: \"" + richText.at(i) + "\" }";
408 QQmlComponent textComponent(&engine);
409 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
410 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
412 QVERIFY(textObject != 0);
413 QCOMPARE(textObject->width(), 30.);
414 QVERIFY(textObject->height() > textHeight);
416 qreal oldHeight = textObject->height();
417 textObject->setWidth(100);
418 QVERIFY(textObject->height() < oldHeight);
423 // richtext again with a fixed height
424 for (int i = 0; i < richText.size(); i++)
426 QString componentStr = "import QtQuick 2.0\nText { wrapMode: Text.WordWrap; width: 30; height: 50; text: \"" + richText.at(i) + "\" }";
427 QQmlComponent textComponent(&engine);
428 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
429 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
431 QVERIFY(textObject != 0);
432 QCOMPARE(textObject->width(), 30.);
433 QVERIFY(textObject->implicitHeight() > textHeight);
435 qreal oldHeight = textObject->implicitHeight();
436 textObject->setWidth(100);
437 QVERIFY(textObject->implicitHeight() < oldHeight);
443 QQmlComponent component(&engine);
444 component.setData("import QtQuick 2.0\n Text {}", QUrl());
445 QScopedPointer<QObject> object(component.create());
446 QQuickText *textObject = qobject_cast<QQuickText *>(object.data());
449 QSignalSpy spy(textObject, SIGNAL(wrapModeChanged()));
451 QCOMPARE(textObject->wrapMode(), QQuickText::NoWrap);
453 textObject->setWrapMode(QQuickText::Wrap);
454 QCOMPARE(textObject->wrapMode(), QQuickText::Wrap);
455 QCOMPARE(spy.count(), 1);
457 textObject->setWrapMode(QQuickText::Wrap);
458 QCOMPARE(spy.count(), 1);
460 textObject->setWrapMode(QQuickText::NoWrap);
461 QCOMPARE(textObject->wrapMode(), QQuickText::NoWrap);
462 QCOMPARE(spy.count(), 2);
466 void tst_qquicktext::elide()
468 for (QQuickText::TextElideMode m = QQuickText::ElideLeft; m<=QQuickText::ElideNone; m=QQuickText::TextElideMode(int(m)+1)) {
469 const char* elidename[]={"ElideLeft", "ElideRight", "ElideMiddle", "ElideNone"};
470 QString elide = "elide: Text." + QString(elidename[int(m)]) + ";";
472 // XXX Poor coverage.
475 QQmlComponent textComponent(&engine);
476 textComponent.setData(("import QtQuick 2.0\nText { text: \"\"; "+elide+" width: 100 }").toLatin1(), QUrl::fromLocalFile(""));
477 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
479 QCOMPARE(textObject->elideMode(), m);
480 QCOMPARE(textObject->width(), 100.);
485 for (int i = 0; i < standard.size(); i++)
487 QString componentStr = "import QtQuick 2.0\nText { "+elide+" width: 100; text: \"" + standard.at(i) + "\" }";
488 QQmlComponent textComponent(&engine);
489 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
490 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
492 QCOMPARE(textObject->elideMode(), m);
493 QCOMPARE(textObject->width(), 100.);
495 if (m != QQuickText::ElideNone && !standard.at(i).contains('\n'))
496 QVERIFY(textObject->contentWidth() <= textObject->width());
501 for (int i = 0; i < richText.size(); i++)
503 QString componentStr = "import QtQuick 2.0\nText { "+elide+" width: 100; text: \"" + richText.at(i) + "\" }";
504 QQmlComponent textComponent(&engine);
505 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
506 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
508 QCOMPARE(textObject->elideMode(), m);
509 QCOMPARE(textObject->width(), 100.);
511 if (m != QQuickText::ElideNone && standard.at(i).contains("<br>"))
512 QVERIFY(textObject->contentWidth() <= textObject->width());
519 void tst_qquicktext::multilineElide_data()
521 QTest::addColumn<QQuickText::TextFormat>("format");
522 QTest::newRow("plain") << QQuickText::PlainText;
523 QTest::newRow("styled") << QQuickText::StyledText;
526 void tst_qquicktext::multilineElide()
528 QFETCH(QQuickText::TextFormat, format);
529 QQuickView *window = createView(testFile("multilineelide.qml"));
531 QQuickText *myText = qobject_cast<QQuickText*>(window->rootObject());
532 QVERIFY(myText != 0);
533 myText->setTextFormat(format);
535 QCOMPARE(myText->lineCount(), 3);
536 QCOMPARE(myText->truncated(), true);
538 qreal lineHeight = myText->contentHeight() / 3.;
540 // Set a valid height greater than the truncated content height and ensure the line count is
542 myText->setHeight(200);
543 QCOMPARE(myText->lineCount(), 3);
544 QCOMPARE(myText->truncated(), true);
546 // reduce size and ensure fewer lines are drawn
547 myText->setHeight(lineHeight * 2);
548 QCOMPARE(myText->lineCount(), 2);
550 myText->setHeight(lineHeight);
551 QCOMPARE(myText->lineCount(), 1);
553 myText->setHeight(5);
554 QCOMPARE(myText->lineCount(), 1);
556 myText->setHeight(lineHeight * 3);
557 QCOMPARE(myText->lineCount(), 3);
559 // remove max count and show all lines.
560 myText->setHeight(1000);
561 myText->resetMaximumLineCount();
563 QCOMPARE(myText->truncated(), false);
566 myText->setHeight(lineHeight * 2);
567 QCOMPARE(myText->lineCount(), 2);
568 QCOMPARE(myText->truncated(), true);
570 // change line height
571 myText->setLineHeight(1.1);
572 QCOMPARE(myText->lineCount(), 1);
577 void tst_qquicktext::implicitElide_data()
579 QTest::addColumn<QString>("width");
580 QTest::addColumn<QString>("initialText");
581 QTest::addColumn<QString>("text");
583 QTest::newRow("maximum width, empty")
584 << "Math.min(implicitWidth, 100)"
586 QTest::newRow("maximum width, short")
587 << "Math.min(implicitWidth, 100)"
589 QTest::newRow("maximum width, long")
590 << "Math.min(implicitWidth, 100)"
591 << "the quick brown fox jumped over the lazy dog";
592 QTest::newRow("reset width, empty")
593 << "implicitWidth > 100 ? 100 : undefined"
595 QTest::newRow("reset width, short")
596 << "implicitWidth > 100 ? 100 : undefined"
598 QTest::newRow("reset width, long")
599 << "implicitWidth > 100 ? 100 : undefined"
600 << "the quick brown fox jumped over the lazy dog";
603 void tst_qquicktext::implicitElide()
605 QFETCH(QString, width);
606 QFETCH(QString, initialText);
608 QString componentStr =
609 "import QtQuick 2.0\n"
611 "width: " + width + "\n"
612 "text: \"" + initialText + "\"\n"
613 "elide: Text.ElideRight\n"
615 QQmlComponent textComponent(&engine);
616 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
617 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
619 QVERIFY(textObject->contentWidth() <= textObject->width());
621 textObject->setText("the quick brown fox jumped over");
623 QVERIFY(textObject->contentWidth() > 0);
624 QVERIFY(textObject->contentWidth() <= textObject->width());
627 void tst_qquicktext::textFormat()
630 QQmlComponent textComponent(&engine);
631 textComponent.setData("import QtQuick 2.0\nText { text: \"Hello\"; textFormat: Text.RichText }", QUrl::fromLocalFile(""));
632 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
634 QVERIFY(textObject != 0);
635 QVERIFY(textObject->textFormat() == QQuickText::RichText);
637 QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject);
638 QVERIFY(textPrivate != 0);
639 QVERIFY(textPrivate->richText == true);
644 QQmlComponent textComponent(&engine);
645 textComponent.setData("import QtQuick 2.0\nText { text: \"<b>Hello</b>\" }", QUrl::fromLocalFile(""));
646 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
648 QVERIFY(textObject != 0);
649 QVERIFY(textObject->textFormat() == QQuickText::AutoText);
651 QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject);
652 QVERIFY(textPrivate != 0);
653 QVERIFY(textPrivate->styledText == true);
658 QQmlComponent textComponent(&engine);
659 textComponent.setData("import QtQuick 2.0\nText { text: \"<b>Hello</b>\"; textFormat: Text.PlainText }", QUrl::fromLocalFile(""));
660 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
662 QVERIFY(textObject != 0);
663 QVERIFY(textObject->textFormat() == QQuickText::PlainText);
669 QQmlComponent component(&engine);
670 component.setData("import QtQuick 2.0\n Text {}", QUrl());
671 QScopedPointer<QObject> object(component.create());
672 QQuickText *text = qobject_cast<QQuickText *>(object.data());
675 QSignalSpy spy(text, SIGNAL(textFormatChanged(TextFormat)));
677 QCOMPARE(text->textFormat(), QQuickText::AutoText);
679 text->setTextFormat(QQuickText::StyledText);
680 QCOMPARE(text->textFormat(), QQuickText::StyledText);
681 QCOMPARE(spy.count(), 1);
683 text->setTextFormat(QQuickText::StyledText);
684 QCOMPARE(spy.count(), 1);
686 text->setTextFormat(QQuickText::AutoText);
687 QCOMPARE(text->textFormat(), QQuickText::AutoText);
688 QCOMPARE(spy.count(), 2);
693 void tst_qquicktext::alignments_data()
695 QTest::addColumn<int>("hAlign");
696 QTest::addColumn<int>("vAlign");
697 QTest::addColumn<QString>("expectfile");
699 QTest::newRow("LT") << int(Qt::AlignLeft) << int(Qt::AlignTop) << testFile("alignments_lt.png");
700 QTest::newRow("RT") << int(Qt::AlignRight) << int(Qt::AlignTop) << testFile("alignments_rt.png");
701 QTest::newRow("CT") << int(Qt::AlignHCenter) << int(Qt::AlignTop) << testFile("alignments_ct.png");
703 QTest::newRow("LB") << int(Qt::AlignLeft) << int(Qt::AlignBottom) << testFile("alignments_lb.png");
704 QTest::newRow("RB") << int(Qt::AlignRight) << int(Qt::AlignBottom) << testFile("alignments_rb.png");
705 QTest::newRow("CB") << int(Qt::AlignHCenter) << int(Qt::AlignBottom) << testFile("alignments_cb.png");
707 QTest::newRow("LC") << int(Qt::AlignLeft) << int(Qt::AlignVCenter) << testFile("alignments_lc.png");
708 QTest::newRow("RC") << int(Qt::AlignRight) << int(Qt::AlignVCenter) << testFile("alignments_rc.png");
709 QTest::newRow("CC") << int(Qt::AlignHCenter) << int(Qt::AlignVCenter) << testFile("alignments_cc.png");
713 void tst_qquicktext::alignments()
715 QSKIP("Text alignment pixmap comparison tests will not work with scenegraph");
716 #if (0)// No widgets in scenegraph
719 QFETCH(QString, expectfile);
721 QQuickView *window = createView(testFile("alignments.qml"));
723 window->requestActivateWindow();
725 QTRY_COMPARE(QGuiApplication::activeWindow(), static_cast<QWidget *>(window));
727 QObject *ob = window->rootObject();
729 ob->setProperty("horizontalAlignment",hAlign);
730 ob->setProperty("verticalAlignment",vAlign);
731 QTRY_COMPARE(ob->property("running").toBool(),false);
732 QImage actual(window->width(), window->height(), QImage::Format_RGB32);
733 actual.fill(qRgb(255,255,255));
737 QImage expect(expectfile);
738 if (QGuiApplicationPrivate::graphics_system_name == "raster" || QGuiApplicationPrivate::graphics_system_name == "") {
739 QCOMPARE(actual,expect);
745 //the alignment tests may be trivial o.oa
746 void tst_qquicktext::horizontalAlignment()
748 //test one align each, and then test if two align fails.
750 for (int i = 0; i < standard.size(); i++)
752 for (int j=0; j < horizontalAlignmentmentStrings.size(); j++)
754 QString componentStr = "import QtQuick 2.0\nText { horizontalAlignment: \"" + horizontalAlignmentmentStrings.at(j) + "\"; text: \"" + standard.at(i) + "\" }";
755 QQmlComponent textComponent(&engine);
756 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
757 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
759 QCOMPARE((int)textObject->hAlign(), (int)horizontalAlignmentments.at(j));
765 for (int i = 0; i < richText.size(); i++)
767 for (int j=0; j < horizontalAlignmentmentStrings.size(); j++)
769 QString componentStr = "import QtQuick 2.0\nText { horizontalAlignment: \"" + horizontalAlignmentmentStrings.at(j) + "\"; text: \"" + richText.at(i) + "\" }";
770 QQmlComponent textComponent(&engine);
771 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
772 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
774 QCOMPARE((int)textObject->hAlign(), (int)horizontalAlignmentments.at(j));
782 void tst_qquicktext::horizontalAlignment_RightToLeft()
784 QQuickView *window = createView(testFile("horizontalAlignment_RightToLeft.qml"));
785 QQuickText *text = window->rootObject()->findChild<QQuickText*>("text");
789 QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(text);
790 QVERIFY(textPrivate != 0);
792 QTRY_VERIFY(textPrivate->layout.lineCount());
794 // implicit alignment should follow the reading direction of RTL text
795 QCOMPARE(text->hAlign(), QQuickText::AlignRight);
796 QCOMPARE(text->effectiveHAlign(), text->hAlign());
797 QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > window->width()/2);
799 // explicitly left aligned text
800 text->setHAlign(QQuickText::AlignLeft);
801 QCOMPARE(text->hAlign(), QQuickText::AlignLeft);
802 QCOMPARE(text->effectiveHAlign(), text->hAlign());
803 QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() < window->width()/2);
805 // explicitly right aligned text
806 text->setHAlign(QQuickText::AlignRight);
807 QCOMPARE(text->hAlign(), QQuickText::AlignRight);
808 QCOMPARE(text->effectiveHAlign(), text->hAlign());
809 QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > window->width()/2);
811 // change to rich text
812 QString textString = text->text();
813 text->setText(QString("<i>") + textString + QString("</i>"));
814 text->setTextFormat(QQuickText::RichText);
817 // implicitly aligned rich text should follow the reading direction of text
818 QCOMPARE(text->hAlign(), QQuickText::AlignRight);
819 QCOMPARE(text->effectiveHAlign(), text->hAlign());
820 QVERIFY(textPrivate->extra.isAllocated());
821 QVERIFY(textPrivate->extra->doc->defaultTextOption().alignment() & Qt::AlignLeft);
823 // explicitly left aligned rich text
824 text->setHAlign(QQuickText::AlignLeft);
825 QCOMPARE(text->hAlign(), QQuickText::AlignLeft);
826 QCOMPARE(text->effectiveHAlign(), text->hAlign());
827 QVERIFY(textPrivate->extra->doc->defaultTextOption().alignment() & Qt::AlignRight);
829 // explicitly right aligned rich text
830 text->setHAlign(QQuickText::AlignRight);
831 QCOMPARE(text->hAlign(), QQuickText::AlignRight);
832 QCOMPARE(text->effectiveHAlign(), text->hAlign());
833 QVERIFY(textPrivate->extra->doc->defaultTextOption().alignment() & Qt::AlignLeft);
835 text->setText(textString);
836 text->setTextFormat(QQuickText::PlainText);
838 // explicitly center aligned
839 text->setHAlign(QQuickText::AlignHCenter);
840 QCOMPARE(text->hAlign(), QQuickText::AlignHCenter);
841 QCOMPARE(text->effectiveHAlign(), text->hAlign());
842 QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() < window->width()/2);
843 QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().right() > window->width()/2);
845 // reseted alignment should go back to following the text reading direction
847 QCOMPARE(text->hAlign(), QQuickText::AlignRight);
848 QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > window->width()/2);
850 // mirror the text item
851 QQuickItemPrivate::get(text)->setLayoutMirror(true);
853 // mirrored implicit alignment should continue to follow the reading direction of the text
854 QCOMPARE(text->hAlign(), QQuickText::AlignRight);
855 QCOMPARE(text->effectiveHAlign(), QQuickText::AlignRight);
856 QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > window->width()/2);
858 // mirrored explicitly right aligned behaves as left aligned
859 text->setHAlign(QQuickText::AlignRight);
860 QCOMPARE(text->hAlign(), QQuickText::AlignRight);
861 QCOMPARE(text->effectiveHAlign(), QQuickText::AlignLeft);
862 QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() < window->width()/2);
864 // mirrored explicitly left aligned behaves as right aligned
865 text->setHAlign(QQuickText::AlignLeft);
866 QCOMPARE(text->hAlign(), QQuickText::AlignLeft);
867 QCOMPARE(text->effectiveHAlign(), QQuickText::AlignRight);
868 QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > window->width()/2);
871 QQuickItemPrivate::get(text)->setLayoutMirror(false);
874 // English text should be implicitly left aligned
875 text->setText("Hello world!");
876 QCOMPARE(text->hAlign(), QQuickText::AlignLeft);
877 QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() < window->width()/2);
879 // empty text with implicit alignment follows the system locale-based
880 // keyboard input direction from QInputMethod::inputDirection()
882 QCOMPARE(text->hAlign(), qApp->inputMethod()->inputDirection() == Qt::LeftToRight ?
883 QQuickText::AlignLeft : QQuickText::AlignRight);
884 text->setHAlign(QQuickText::AlignRight);
885 QCOMPARE(text->hAlign(), QQuickText::AlignRight);
889 // alignment of Text with no text set to it
890 QString componentStr = "import QtQuick 2.0\nText {}";
891 QQmlComponent textComponent(&engine);
892 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
893 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
894 QCOMPARE(textObject->hAlign(), qApp->inputMethod()->inputDirection() == Qt::LeftToRight ?
895 QQuickText::AlignLeft : QQuickText::AlignRight);
899 int tst_qquicktext::numberOfNonWhitePixels(int fromX, int toX, const QImage &image)
902 for (int x = fromX; x < toX; ++x) {
903 for (int y = 0; y < image.height(); ++y) {
904 if (image.pixel(x, y) != qRgb(255, 255, 255))
911 void tst_qquicktext::hAlignImplicitWidth()
913 QQuickView view(testFileUrl("hAlignImplicitWidth.qml"));
915 view.requestActivateWindow();
916 QVERIFY(QTest::qWaitForWindowActive(&view));
918 QQuickText *text = view.rootObject()->findChild<QQuickText*>("textItem");
923 QImage image = view.grabWindow();
924 int left = numberOfNonWhitePixels(0, image.width() / 3, image);
925 int mid = numberOfNonWhitePixels(image.width() / 3, 2 * image.width() / 3, image);
926 int right = numberOfNonWhitePixels( 2 * image.width() / 3, image.width(), image);
928 QVERIFY(mid > right);
932 text->setHAlign(QQuickText::AlignHCenter);
933 QImage image = view.grabWindow();
934 int left = numberOfNonWhitePixels(0, image.width() / 3, image);
935 int mid = numberOfNonWhitePixels(image.width() / 3, 2 * image.width() / 3, image);
936 int right = numberOfNonWhitePixels( 2 * image.width() / 3, image.width(), image);
938 QVERIFY(mid > right);
942 text->setHAlign(QQuickText::AlignRight);
943 QImage image = view.grabWindow();
944 int left = numberOfNonWhitePixels(0, image.width() / 3, image);
945 int mid = numberOfNonWhitePixels(image.width() / 3, 2 * image.width() / 3, image);
946 int right = numberOfNonWhitePixels( 2 * image.width() / 3, image.width(), image);
948 QVERIFY(mid < right);
952 void tst_qquicktext::verticalAlignment()
954 //test one align each, and then test if two align fails.
956 for (int i = 0; i < standard.size(); i++)
958 for (int j=0; j < verticalAlignmentmentStrings.size(); j++)
960 QString componentStr = "import QtQuick 2.0\nText { verticalAlignment: \"" + verticalAlignmentmentStrings.at(j) + "\"; text: \"" + standard.at(i) + "\" }";
961 QQmlComponent textComponent(&engine);
962 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
963 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
965 QVERIFY(textObject != 0);
966 QCOMPARE((int)textObject->vAlign(), (int)verticalAlignmentments.at(j));
972 for (int i = 0; i < richText.size(); i++)
974 for (int j=0; j < verticalAlignmentmentStrings.size(); j++)
976 QString componentStr = "import QtQuick 2.0\nText { verticalAlignment: \"" + verticalAlignmentmentStrings.at(j) + "\"; text: \"" + richText.at(i) + "\" }";
977 QQmlComponent textComponent(&engine);
978 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
979 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
981 QVERIFY(textObject != 0);
982 QCOMPARE((int)textObject->vAlign(), (int)verticalAlignmentments.at(j));
990 void tst_qquicktext::font()
992 //test size, then bold, then italic, then family
994 QString componentStr = "import QtQuick 2.0\nText { font.pointSize: 40; text: \"Hello World\" }";
995 QQmlComponent textComponent(&engine);
996 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
997 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
999 QCOMPARE(textObject->font().pointSize(), 40);
1000 QCOMPARE(textObject->font().bold(), false);
1001 QCOMPARE(textObject->font().italic(), false);
1007 QString componentStr = "import QtQuick 2.0\nText { font.pixelSize: 40; text: \"Hello World\" }";
1008 QQmlComponent textComponent(&engine);
1009 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1010 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1012 QCOMPARE(textObject->font().pixelSize(), 40);
1013 QCOMPARE(textObject->font().bold(), false);
1014 QCOMPARE(textObject->font().italic(), false);
1020 QString componentStr = "import QtQuick 2.0\nText { font.bold: true; text: \"Hello World\" }";
1021 QQmlComponent textComponent(&engine);
1022 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1023 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1025 QCOMPARE(textObject->font().bold(), true);
1026 QCOMPARE(textObject->font().italic(), false);
1032 QString componentStr = "import QtQuick 2.0\nText { font.italic: true; text: \"Hello World\" }";
1033 QQmlComponent textComponent(&engine);
1034 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1035 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1037 QCOMPARE(textObject->font().italic(), true);
1038 QCOMPARE(textObject->font().bold(), false);
1044 QString componentStr = "import QtQuick 2.0\nText { font.family: \"Helvetica\"; text: \"Hello World\" }";
1045 QQmlComponent textComponent(&engine);
1046 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1047 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1049 QCOMPARE(textObject->font().family(), QString("Helvetica"));
1050 QCOMPARE(textObject->font().bold(), false);
1051 QCOMPARE(textObject->font().italic(), false);
1057 QString componentStr = "import QtQuick 2.0\nText { font.family: \"\"; text: \"Hello World\" }";
1058 QQmlComponent textComponent(&engine);
1059 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1060 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1062 QCOMPARE(textObject->font().family(), QString(""));
1068 void tst_qquicktext::style()
1071 for (int i = 0; i < styles.size(); i++)
1073 QString componentStr = "import QtQuick 2.0\nText { style: \"" + styleStrings.at(i) + "\"; styleColor: \"white\"; text: \"Hello World\" }";
1074 QQmlComponent textComponent(&engine);
1075 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1076 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1078 QCOMPARE((int)textObject->style(), (int)styles.at(i));
1079 QCOMPARE(textObject->styleColor(), QColor("white"));
1083 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello World\" }";
1084 QQmlComponent textComponent(&engine);
1085 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1086 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1088 QRectF brPre = textObject->boundingRect();
1089 textObject->setStyle(QQuickText::Outline);
1090 QRectF brPost = textObject->boundingRect();
1092 QVERIFY(brPre.width() < brPost.width());
1093 QVERIFY(brPre.height() < brPost.height());
1098 void tst_qquicktext::color()
1101 for (int i = 0; i < colorStrings.size(); i++)
1103 QString componentStr = "import QtQuick 2.0\nText { color: \"" + colorStrings.at(i) + "\"; text: \"Hello World\" }";
1104 QQmlComponent textComponent(&engine);
1105 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1106 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1108 QCOMPARE(textObject->color(), QColor(colorStrings.at(i)));
1109 QCOMPARE(textObject->styleColor(), QColor("black"));
1110 QCOMPARE(textObject->linkColor(), QColor("blue"));
1115 for (int i = 0; i < colorStrings.size(); i++)
1117 QString componentStr = "import QtQuick 2.0\nText { styleColor: \"" + colorStrings.at(i) + "\"; text: \"Hello World\" }";
1118 QQmlComponent textComponent(&engine);
1119 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1120 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1122 QCOMPARE(textObject->styleColor(), QColor(colorStrings.at(i)));
1123 // default color to black?
1124 QCOMPARE(textObject->color(), QColor("black"));
1125 QCOMPARE(textObject->linkColor(), QColor("blue"));
1127 QSignalSpy colorSpy(textObject, SIGNAL(colorChanged()));
1128 QSignalSpy linkColorSpy(textObject, SIGNAL(linkColorChanged()));
1130 textObject->setColor(QColor("white"));
1131 QCOMPARE(textObject->color(), QColor("white"));
1132 QCOMPARE(colorSpy.count(), 1);
1134 textObject->setLinkColor(QColor("black"));
1135 QCOMPARE(textObject->linkColor(), QColor("black"));
1136 QCOMPARE(linkColorSpy.count(), 1);
1138 textObject->setColor(QColor("white"));
1139 QCOMPARE(colorSpy.count(), 1);
1141 textObject->setLinkColor(QColor("black"));
1142 QCOMPARE(linkColorSpy.count(), 1);
1144 textObject->setColor(QColor("black"));
1145 QCOMPARE(textObject->color(), QColor("black"));
1146 QCOMPARE(colorSpy.count(), 2);
1148 textObject->setLinkColor(QColor("blue"));
1149 QCOMPARE(textObject->linkColor(), QColor("blue"));
1150 QCOMPARE(linkColorSpy.count(), 2);
1155 for (int i = 0; i < colorStrings.size(); i++)
1157 QString componentStr = "import QtQuick 2.0\nText { linkColor: \"" + colorStrings.at(i) + "\"; text: \"Hello World\" }";
1158 QQmlComponent textComponent(&engine);
1159 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1160 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1162 QCOMPARE(textObject->styleColor(), QColor("black"));
1163 QCOMPARE(textObject->color(), QColor("black"));
1164 QCOMPARE(textObject->linkColor(), QColor(colorStrings.at(i)));
1169 for (int i = 0; i < colorStrings.size(); i++)
1171 for (int j = 0; j < colorStrings.size(); j++)
1173 QString componentStr = "import QtQuick 2.0\nText { "
1174 "color: \"" + colorStrings.at(i) + "\"; "
1175 "styleColor: \"" + colorStrings.at(j) + "\"; "
1176 "linkColor: \"" + colorStrings.at(j) + "\"; "
1177 "text: \"Hello World\" }";
1178 QQmlComponent textComponent(&engine);
1179 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1180 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1182 QCOMPARE(textObject->color(), QColor(colorStrings.at(i)));
1183 QCOMPARE(textObject->styleColor(), QColor(colorStrings.at(j)));
1184 QCOMPARE(textObject->linkColor(), QColor(colorStrings.at(j)));
1190 QString colorStr = "#AA001234";
1191 QColor testColor("#001234");
1192 testColor.setAlpha(170);
1194 QString componentStr = "import QtQuick 2.0\nText { color: \"" + colorStr + "\"; text: \"Hello World\" }";
1195 QQmlComponent textComponent(&engine);
1196 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1197 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1199 QCOMPARE(textObject->color(), testColor);
1203 QString colorStr = "#001234";
1204 QColor testColor(colorStr);
1206 QString componentStr = "import QtQuick 2.0\nText { color: \"" + colorStr + "\"; text: \"Hello World\" }";
1207 QQmlComponent textComponent(&engine);
1208 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1209 QScopedPointer<QObject> object(textComponent.create());
1210 QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
1212 QSignalSpy spy(textObject, SIGNAL(colorChanged()));
1214 QCOMPARE(textObject->color(), testColor);
1215 textObject->setColor(testColor);
1216 QCOMPARE(textObject->color(), testColor);
1217 QCOMPARE(spy.count(), 0);
1219 testColor = QColor("black");
1220 textObject->setColor(testColor);
1221 QCOMPARE(textObject->color(), testColor);
1222 QCOMPARE(spy.count(), 1);
1224 QString colorStr = "#001234";
1225 QColor testColor(colorStr);
1227 QString componentStr = "import QtQuick 2.0\nText { styleColor: \"" + colorStr + "\"; text: \"Hello World\" }";
1228 QQmlComponent textComponent(&engine);
1229 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1230 QScopedPointer<QObject> object(textComponent.create());
1231 QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
1233 QSignalSpy spy(textObject, SIGNAL(styleColorChanged()));
1235 QCOMPARE(textObject->styleColor(), testColor);
1236 textObject->setStyleColor(testColor);
1237 QCOMPARE(textObject->styleColor(), testColor);
1238 QCOMPARE(spy.count(), 0);
1240 testColor = QColor("black");
1241 textObject->setStyleColor(testColor);
1242 QCOMPARE(textObject->styleColor(), testColor);
1243 QCOMPARE(spy.count(), 1);
1245 QString colorStr = "#001234";
1246 QColor testColor(colorStr);
1248 QString componentStr = "import QtQuick 2.0\nText { linkColor: \"" + colorStr + "\"; text: \"Hello World\" }";
1249 QQmlComponent textComponent(&engine);
1250 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1251 QScopedPointer<QObject> object(textComponent.create());
1252 QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
1254 QSignalSpy spy(textObject, SIGNAL(linkColorChanged()));
1256 QCOMPARE(textObject->linkColor(), testColor);
1257 textObject->setLinkColor(testColor);
1258 QCOMPARE(textObject->linkColor(), testColor);
1259 QCOMPARE(spy.count(), 0);
1261 testColor = QColor("black");
1262 textObject->setLinkColor(testColor);
1263 QCOMPARE(textObject->linkColor(), testColor);
1264 QCOMPARE(spy.count(), 1);
1268 void tst_qquicktext::smooth()
1270 for (int i = 0; i < standard.size(); i++)
1273 QString componentStr = "import QtQuick 2.0\nText { smooth: false; text: \"" + standard.at(i) + "\" }";
1274 QQmlComponent textComponent(&engine);
1275 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1276 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1277 QCOMPARE(textObject->smooth(), false);
1282 QString componentStr = "import QtQuick 2.0\nText { text: \"" + standard.at(i) + "\" }";
1283 QQmlComponent textComponent(&engine);
1284 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1285 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1286 QCOMPARE(textObject->smooth(), true);
1291 for (int i = 0; i < richText.size(); i++)
1294 QString componentStr = "import QtQuick 2.0\nText { smooth: false; text: \"" + richText.at(i) + "\" }";
1295 QQmlComponent textComponent(&engine);
1296 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1297 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1298 QCOMPARE(textObject->smooth(), false);
1303 QString componentStr = "import QtQuick 2.0\nText { text: \"" + richText.at(i) + "\" }";
1304 QQmlComponent textComponent(&engine);
1305 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1306 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1307 QCOMPARE(textObject->smooth(), true);
1314 void tst_qquicktext::renderType()
1316 QQmlComponent component(&engine);
1317 component.setData("import QtQuick 2.0\n Text {}", QUrl());
1318 QScopedPointer<QObject> object(component.create());
1319 QQuickText *text = qobject_cast<QQuickText *>(object.data());
1322 QSignalSpy spy(text, SIGNAL(renderTypeChanged()));
1324 QCOMPARE(text->renderType(), QQuickText::QtRendering);
1326 text->setRenderType(QQuickText::NativeRendering);
1327 QCOMPARE(text->renderType(), QQuickText::NativeRendering);
1328 QCOMPARE(spy.count(), 1);
1330 text->setRenderType(QQuickText::NativeRendering);
1331 QCOMPARE(spy.count(), 1);
1333 text->setRenderType(QQuickText::QtRendering);
1334 QCOMPARE(text->renderType(), QQuickText::QtRendering);
1335 QCOMPARE(spy.count(), 2);
1338 void tst_qquicktext::weight()
1341 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
1342 QQmlComponent textComponent(&engine);
1343 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1344 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1346 QVERIFY(textObject != 0);
1347 QCOMPARE((int)textObject->font().weight(), (int)QQuickFontValueType::Normal);
1352 QString componentStr = "import QtQuick 2.0\nText { font.weight: \"Bold\"; text: \"Hello world!\" }";
1353 QQmlComponent textComponent(&engine);
1354 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1355 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1357 QVERIFY(textObject != 0);
1358 QCOMPARE((int)textObject->font().weight(), (int)QQuickFontValueType::Bold);
1364 void tst_qquicktext::underline()
1366 QQuickView view(testFileUrl("underline.qml"));
1368 view.requestActivateWindow();
1369 QVERIFY(QTest::qWaitForWindowActive(&view));
1370 QQuickText *textObject = view.rootObject()->findChild<QQuickText*>("myText");
1371 QVERIFY(textObject != 0);
1372 QCOMPARE(textObject->font().overline(), false);
1373 QCOMPARE(textObject->font().underline(), true);
1374 QCOMPARE(textObject->font().strikeOut(), false);
1377 void tst_qquicktext::overline()
1379 QQuickView view(testFileUrl("overline.qml"));
1381 view.requestActivateWindow();
1382 QVERIFY(QTest::qWaitForWindowActive(&view));
1383 QQuickText *textObject = view.rootObject()->findChild<QQuickText*>("myText");
1384 QVERIFY(textObject != 0);
1385 QCOMPARE(textObject->font().overline(), true);
1386 QCOMPARE(textObject->font().underline(), false);
1387 QCOMPARE(textObject->font().strikeOut(), false);
1390 void tst_qquicktext::strikeout()
1392 QQuickView view(testFileUrl("strikeout.qml"));
1394 view.requestActivateWindow();
1395 QVERIFY(QTest::qWaitForWindowActive(&view));
1396 QQuickText *textObject = view.rootObject()->findChild<QQuickText*>("myText");
1397 QVERIFY(textObject != 0);
1398 QCOMPARE(textObject->font().overline(), false);
1399 QCOMPARE(textObject->font().underline(), false);
1400 QCOMPARE(textObject->font().strikeOut(), true);
1403 void tst_qquicktext::capitalization()
1406 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
1407 QQmlComponent textComponent(&engine);
1408 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1409 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1411 QVERIFY(textObject != 0);
1412 QCOMPARE((int)textObject->font().capitalization(), (int)QQuickFontValueType::MixedCase);
1417 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.capitalization: \"AllUppercase\" }";
1418 QQmlComponent textComponent(&engine);
1419 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1420 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1422 QVERIFY(textObject != 0);
1423 QCOMPARE((int)textObject->font().capitalization(), (int)QQuickFontValueType::AllUppercase);
1428 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.capitalization: \"AllLowercase\" }";
1429 QQmlComponent textComponent(&engine);
1430 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1431 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1433 QVERIFY(textObject != 0);
1434 QCOMPARE((int)textObject->font().capitalization(), (int)QQuickFontValueType::AllLowercase);
1439 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.capitalization: \"SmallCaps\" }";
1440 QQmlComponent textComponent(&engine);
1441 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1442 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1444 QVERIFY(textObject != 0);
1445 QCOMPARE((int)textObject->font().capitalization(), (int)QQuickFontValueType::SmallCaps);
1450 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.capitalization: \"Capitalize\" }";
1451 QQmlComponent textComponent(&engine);
1452 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1453 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1455 QVERIFY(textObject != 0);
1456 QCOMPARE((int)textObject->font().capitalization(), (int)QQuickFontValueType::Capitalize);
1462 void tst_qquicktext::letterSpacing()
1465 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
1466 QQmlComponent textComponent(&engine);
1467 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1468 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1470 QVERIFY(textObject != 0);
1471 QCOMPARE(textObject->font().letterSpacing(), 0.0);
1476 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.letterSpacing: -2 }";
1477 QQmlComponent textComponent(&engine);
1478 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1479 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1481 QVERIFY(textObject != 0);
1482 QCOMPARE(textObject->font().letterSpacing(), -2.);
1487 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.letterSpacing: 3 }";
1488 QQmlComponent textComponent(&engine);
1489 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1490 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1492 QVERIFY(textObject != 0);
1493 QCOMPARE(textObject->font().letterSpacing(), 3.);
1499 void tst_qquicktext::wordSpacing()
1502 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
1503 QQmlComponent textComponent(&engine);
1504 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1505 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1507 QVERIFY(textObject != 0);
1508 QCOMPARE(textObject->font().wordSpacing(), 0.0);
1513 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.wordSpacing: -50 }";
1514 QQmlComponent textComponent(&engine);
1515 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1516 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1518 QVERIFY(textObject != 0);
1519 QCOMPARE(textObject->font().wordSpacing(), -50.);
1524 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.wordSpacing: 200 }";
1525 QQmlComponent textComponent(&engine);
1526 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1527 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1529 QVERIFY(textObject != 0);
1530 QCOMPARE(textObject->font().wordSpacing(), 200.);
1536 class EventSender : public QQuickItem
1539 void sendEvent(QMouseEvent *event) {
1540 if (event->type() == QEvent::MouseButtonPress)
1541 mousePressEvent(event);
1542 else if (event->type() == QEvent::MouseButtonRelease)
1543 mouseReleaseEvent(event);
1544 else if (event->type() == QEvent::MouseMove)
1545 mouseMoveEvent(event);
1547 qWarning() << "Trying to send unsupported event type";
1551 class LinkTest : public QObject
1560 void linkClicked(QString l) { link = l; }
1566 TextMetrics(const QString &text, Qt::TextElideMode elideMode = Qt::ElideNone)
1568 QString adjustedText = text;
1569 adjustedText.replace(QLatin1Char('\n'), QChar(QChar::LineSeparator));
1570 if (elideMode == Qt::ElideLeft)
1571 adjustedText = QChar(0x2026) + adjustedText;
1572 else if (elideMode == Qt::ElideRight)
1573 adjustedText = adjustedText + QChar(0x2026);
1575 layout.setText(adjustedText);
1577 option.setUseDesignMetrics(true);
1578 layout.setTextOption(option);
1580 layout.beginLayout();
1582 QTextLine line = layout.createLine();
1583 while (line.isValid()) {
1584 line.setLineWidth(FLT_MAX);
1585 line.setPosition(QPointF(0, height));
1586 height += line.height();
1587 line = layout.createLine();
1592 qreal width() const { return layout.maximumWidth(); }
1594 QRectF characterRectangle(
1596 int hAlign = Qt::AlignLeft,
1597 int vAlign = Qt::AlignTop,
1598 const QSizeF &bounds = QSizeF(240, 320)) const
1602 case Qt::AlignBottom:
1603 dy = bounds.height() - layout.boundingRect().height();
1605 case Qt::AlignVCenter:
1606 dy = (bounds.height() - layout.boundingRect().height()) / 2;
1612 for (int i = 0; i < layout.lineCount(); ++i) {
1613 QTextLine line = layout.lineAt(i);
1614 if (position >= line.textStart() + line.textLength())
1618 case Qt::AlignRight:
1619 dx = bounds.width() - line.naturalTextWidth();
1621 case Qt::AlignHCenter:
1622 dx = (bounds.width() - line.naturalTextWidth()) / 2;
1629 rect.setLeft(dx + line.cursorToX(position, QTextLine::Leading));
1630 rect.setRight(dx + line.cursorToX(position, QTextLine::Trailing));
1631 rect.setTop(dy + line.y());
1632 rect.setBottom(dy + line.y() + line.height());
1643 typedef QVector<QPointF> PointVector;
1644 Q_DECLARE_METATYPE(PointVector);
1646 void tst_qquicktext::clickLink_data()
1648 QTest::addColumn<QString>("text");
1649 QTest::addColumn<qreal>("width");
1650 QTest::addColumn<QString>("bindings");
1651 QTest::addColumn<PointVector>("mousePositions");
1652 QTest::addColumn<QString>("link");
1654 const QString singleLineText = "this text has a <a href=\\\"http://qt-project.org/single\\\">link</a> in it";
1655 const QString singleLineLink = "http://qt-project.org/single";
1656 const QString multipleLineText = "this text<br/>has <a href=\\\"http://qt-project.org/multiple\\\">multiple<br/>lines</a> in it";
1657 const QString multipleLineLink = "http://qt-project.org/multiple";
1658 const QString nestedText = "this text has a <a href=\\\"http://qt-project.org/outer\\\">nested <a href=\\\"http://qt-project.org/inner\\\">link</a> in it</a>";
1659 const QString outerLink = "http://qt-project.org/outer";
1660 const QString innerLink = "http://qt-project.org/inner";
1663 const TextMetrics metrics("this text has a link in it");
1665 QTest::newRow("click on link")
1666 << singleLineText << 240.
1668 << (PointVector() << metrics.characterRectangle(18).center())
1670 QTest::newRow("click on text")
1671 << singleLineText << 240.
1673 << (PointVector() << metrics.characterRectangle(13).center())
1675 QTest::newRow("drag within link")
1676 << singleLineText << 240.
1679 << metrics.characterRectangle(17).center()
1680 << metrics.characterRectangle(19).center())
1682 QTest::newRow("drag away from link")
1683 << singleLineText << 240.
1686 << metrics.characterRectangle(18).center()
1687 << metrics.characterRectangle(13).center())
1689 QTest::newRow("drag on to link")
1690 << singleLineText << 240.
1693 << metrics.characterRectangle(13).center()
1694 << metrics.characterRectangle(18).center())
1696 QTest::newRow("click on bottom right aligned link")
1697 << singleLineText << 240.
1698 << "horizontalAlignment: Text.AlignRight; verticalAlignment: Text.AlignBottom"
1699 << (PointVector() << metrics.characterRectangle(18, Qt::AlignRight, Qt::AlignBottom).center())
1701 QTest::newRow("click on center aligned link")
1702 << singleLineText << 240.
1703 << "horizontalAlignment: Text.AlignHCenter; verticalAlignment: Text.AlignVCenter"
1704 << (PointVector() << metrics.characterRectangle(18, Qt::AlignHCenter, Qt::AlignVCenter).center())
1706 QTest::newRow("click on rich text link")
1707 << singleLineText << 240.
1708 << "textFormat: Text.RichText"
1709 << (PointVector() << metrics.characterRectangle(18).center())
1711 QTest::newRow("click on rich text")
1712 << singleLineText << 240.
1713 << "textFormat: Text.RichText"
1714 << (PointVector() << metrics.characterRectangle(13).center())
1716 QTest::newRow("click on bottom right aligned rich text link")
1717 << singleLineText << 240.
1718 << "textFormat: Text.RichText; horizontalAlignment: Text.AlignRight; verticalAlignment: Text.AlignBottom"
1719 << (PointVector() << metrics.characterRectangle(18, Qt::AlignRight, Qt::AlignBottom).center())
1721 QTest::newRow("click on center aligned rich text link")
1722 << singleLineText << 240.
1723 << "textFormat: Text.RichText; horizontalAlignment: Text.AlignHCenter; verticalAlignment: Text.AlignVCenter"
1724 << (PointVector() << metrics.characterRectangle(18, Qt::AlignHCenter, Qt::AlignVCenter).center())
1727 const TextMetrics metrics("this text has a li", Qt::ElideRight);
1728 QTest::newRow("click on right elided link")
1729 << singleLineText << metrics.width() + 2
1730 << "elide: Text.ElideRight"
1731 << (PointVector() << metrics.characterRectangle(17).center())
1734 const TextMetrics metrics("ink in it", Qt::ElideLeft);
1735 QTest::newRow("click on left elided link")
1736 << singleLineText << metrics.width() + 2
1737 << "elide: Text.ElideLeft"
1738 << (PointVector() << metrics.characterRectangle(2).center())
1741 const TextMetrics metrics("this text\nhas multiple\nlines in it");
1742 QTest::newRow("click on second line")
1743 << multipleLineText << 240.
1745 << (PointVector() << metrics.characterRectangle(18).center())
1746 << multipleLineLink;
1747 QTest::newRow("click on third line")
1748 << multipleLineText << 240.
1750 << (PointVector() << metrics.characterRectangle(25).center())
1751 << multipleLineLink;
1752 QTest::newRow("drag from second line to third")
1753 << multipleLineText << 240.
1756 << metrics.characterRectangle(18).center()
1757 << metrics.characterRectangle(25).center())
1758 << multipleLineLink;
1759 QTest::newRow("click on rich text second line")
1760 << multipleLineText << 240.
1761 << "textFormat: Text.RichText"
1762 << (PointVector() << metrics.characterRectangle(18).center())
1763 << multipleLineLink;
1764 QTest::newRow("click on rich text third line")
1765 << multipleLineText << 240.
1766 << "textFormat: Text.RichText"
1767 << (PointVector() << metrics.characterRectangle(25).center())
1768 << multipleLineLink;
1769 QTest::newRow("drag rich text from second line to third")
1770 << multipleLineText << 240.
1771 << "textFormat: Text.RichText"
1773 << metrics.characterRectangle(18).center()
1774 << metrics.characterRectangle(25).center())
1775 << multipleLineLink;
1777 const TextMetrics metrics("this text has a nested link in it");
1778 QTest::newRow("click on left outer link")
1779 << nestedText << 240.
1781 << (PointVector() << metrics.characterRectangle(22).center())
1783 QTest::newRow("click on right outer link")
1784 << nestedText << 240.
1786 << (PointVector() << metrics.characterRectangle(27).center())
1788 QTest::newRow("click on inner link left")
1789 << nestedText << 240.
1791 << (PointVector() << metrics.characterRectangle(23).center())
1793 QTest::newRow("click on inner link right")
1794 << nestedText << 240.
1796 << (PointVector() << metrics.characterRectangle(26).center())
1798 QTest::newRow("drag from inner to outer link")
1799 << nestedText << 240.
1802 << metrics.characterRectangle(25).center()
1803 << metrics.characterRectangle(30).center())
1805 QTest::newRow("drag from outer to inner link")
1806 << nestedText << 240.
1809 << metrics.characterRectangle(30).center()
1810 << metrics.characterRectangle(25).center())
1812 QTest::newRow("click on left outer rich text link")
1813 << nestedText << 240.
1814 << "textFormat: Text.RichText"
1815 << (PointVector() << metrics.characterRectangle(22).center())
1817 QTest::newRow("click on right outer rich text link")
1818 << nestedText << 240.
1819 << "textFormat: Text.RichText"
1820 << (PointVector() << metrics.characterRectangle(27).center())
1822 QTest::newRow("click on inner rich text link left")
1823 << nestedText << 240.
1824 << "textFormat: Text.RichText"
1825 << (PointVector() << metrics.characterRectangle(23).center())
1827 QTest::newRow("click on inner rich text link right")
1828 << nestedText << 240.
1829 << "textFormat: Text.RichText"
1830 << (PointVector() << metrics.characterRectangle(26).center())
1832 QTest::newRow("drag from inner to outer rich text link")
1833 << nestedText << 240.
1834 << "textFormat: Text.RichText"
1836 << metrics.characterRectangle(25).center()
1837 << metrics.characterRectangle(30).center())
1839 QTest::newRow("drag from outer to inner rich text link")
1840 << nestedText << 240.
1841 << "textFormat: Text.RichText"
1843 << metrics.characterRectangle(30).center()
1844 << metrics.characterRectangle(25).center())
1849 void tst_qquicktext::clickLink()
1851 QFETCH(QString, text);
1852 QFETCH(qreal, width);
1853 QFETCH(QString, bindings);
1854 QFETCH(PointVector, mousePositions);
1855 QFETCH(QString, link);
1857 QString componentStr =
1858 "import QtQuick 2.0\nText {\n"
1859 "width: " + QString::number(width) + "\n"
1861 "text: \"" + text + "\"\n"
1862 "" + bindings + "\n"
1864 QQmlComponent textComponent(&engine);
1865 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1866 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1868 QVERIFY(textObject != 0);
1871 QObject::connect(textObject, SIGNAL(linkActivated(QString)), &test, SLOT(linkClicked(QString)));
1873 QVERIFY(mousePositions.count() > 0);
1875 QPointF mousePosition = mousePositions.first();
1877 QMouseEvent me(QEvent::MouseButtonPress, mousePosition, Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
1878 static_cast<EventSender*>(static_cast<QQuickItem*>(textObject))->sendEvent(&me);
1881 for (int i = 1; i < mousePositions.count(); ++i) {
1882 mousePosition = mousePositions.at(i);
1884 QMouseEvent me(QEvent::MouseMove, mousePosition, Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
1885 static_cast<EventSender*>(static_cast<QQuickItem*>(textObject))->sendEvent(&me);
1889 QMouseEvent me(QEvent::MouseButtonRelease, mousePosition, Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
1890 static_cast<EventSender*>(static_cast<QQuickItem*>(textObject))->sendEvent(&me);
1893 QCOMPARE(test.link, link);
1898 void tst_qquicktext::baseUrl()
1900 QUrl localUrl("file:///tests/text.qml");
1901 QUrl remoteUrl("http://qt.nokia.com/test.qml");
1903 QQmlComponent textComponent(&engine);
1904 textComponent.setData("import QtQuick 2.0\n Text {}", localUrl);
1905 QQuickText *textObject = qobject_cast<QQuickText *>(textComponent.create());
1907 QCOMPARE(textObject->baseUrl(), localUrl);
1909 QSignalSpy spy(textObject, SIGNAL(baseUrlChanged()));
1911 textObject->setBaseUrl(localUrl);
1912 QCOMPARE(textObject->baseUrl(), localUrl);
1913 QCOMPARE(spy.count(), 0);
1915 textObject->setBaseUrl(remoteUrl);
1916 QCOMPARE(textObject->baseUrl(), remoteUrl);
1917 QCOMPARE(spy.count(), 1);
1919 textObject->resetBaseUrl();
1920 QCOMPARE(textObject->baseUrl(), localUrl);
1921 QCOMPARE(spy.count(), 2);
1924 void tst_qquicktext::embeddedImages_data()
1926 QTest::addColumn<QUrl>("qmlfile");
1927 QTest::addColumn<QString>("error");
1928 QTest::newRow("local") << testFileUrl("embeddedImagesLocal.qml") << "";
1929 QTest::newRow("local-error") << testFileUrl("embeddedImagesLocalError.qml")
1930 << testFileUrl("embeddedImagesLocalError.qml").toString()+":3:1: QML Text: Cannot open: " + testFileUrl("http/notexists.png").toString();
1931 QTest::newRow("local") << testFileUrl("embeddedImagesLocalRelative.qml") << "";
1932 QTest::newRow("remote") << testFileUrl("embeddedImagesRemote.qml") << "";
1933 QTest::newRow("remote-error") << testFileUrl("embeddedImagesRemoteError.qml")
1934 << testFileUrl("embeddedImagesRemoteError.qml").toString()+":3:1: QML Text: Error downloading " SERVER_ADDR "/notexists.png - server replied: Not found";
1935 QTest::newRow("remote") << testFileUrl("embeddedImagesRemoteRelative.qml") << "";
1938 void tst_qquicktext::embeddedImages()
1942 QFETCH(QUrl, qmlfile);
1943 QFETCH(QString, error);
1945 TestHTTPServer server(SERVER_PORT);
1946 server.serveDirectory(testFile("http"));
1948 if (!error.isEmpty())
1949 QTest::ignoreMessage(QtWarningMsg, error.toLatin1());
1951 QQuickView *view = new QQuickView(qmlfile);
1953 view->requestActivateWindow();
1954 QVERIFY(QTest::qWaitForWindowActive(view));
1955 QQuickText *textObject = qobject_cast<QQuickText*>(view->rootObject());
1957 QVERIFY(textObject != 0);
1958 QTRY_COMPARE(textObject->resourcesLoading(), 0);
1960 QPixmap pm(testFile("http/exists.png"));
1961 if (error.isEmpty()) {
1962 QCOMPARE(textObject->width(), double(pm.width()));
1963 QCOMPARE(textObject->height(), double(pm.height()));
1965 QVERIFY(16 != pm.width()); // check test is effective
1966 QCOMPARE(textObject->width(), 16.0); // default size of QTextDocument broken image icon
1967 QCOMPARE(textObject->height(), 16.0);
1973 void tst_qquicktext::lineCount()
1975 QQuickView *window = createView(testFile("lineCount.qml"));
1977 QQuickText *myText = window->rootObject()->findChild<QQuickText*>("myText");
1978 QVERIFY(myText != 0);
1980 QVERIFY(myText->lineCount() > 1);
1981 QVERIFY(!myText->truncated());
1982 QCOMPARE(myText->maximumLineCount(), INT_MAX);
1984 myText->setMaximumLineCount(2);
1985 QCOMPARE(myText->lineCount(), 2);
1986 QCOMPARE(myText->truncated(), true);
1987 QCOMPARE(myText->maximumLineCount(), 2);
1989 myText->resetMaximumLineCount();
1990 QCOMPARE(myText->maximumLineCount(), INT_MAX);
1991 QCOMPARE(myText->truncated(), false);
1993 myText->setElideMode(QQuickText::ElideRight);
1994 myText->setMaximumLineCount(2);
1995 QCOMPARE(myText->lineCount(), 2);
1996 QCOMPARE(myText->truncated(), true);
1997 QCOMPARE(myText->maximumLineCount(), 2);
2002 void tst_qquicktext::lineHeight()
2004 QQuickView *window = createView(testFile("lineHeight.qml"));
2006 QQuickText *myText = window->rootObject()->findChild<QQuickText*>("myText");
2007 QVERIFY(myText != 0);
2009 QVERIFY(myText->lineHeight() == 1);
2010 QVERIFY(myText->lineHeightMode() == QQuickText::ProportionalHeight);
2012 qreal h = myText->height();
2013 myText->setLineHeight(1.5);
2014 QCOMPARE(myText->height(), qreal(qCeil(h)) * 1.5);
2016 myText->setLineHeightMode(QQuickText::FixedHeight);
2017 myText->setLineHeight(20);
2018 QCOMPARE(myText->height(), myText->lineCount() * 20.0);
2020 myText->setText("Lorem ipsum sit <b>amet</b>, consectetur adipiscing elit. Integer felis nisl, varius in pretium nec, venenatis non erat. Proin lobortis interdum dictum.");
2021 myText->setLineHeightMode(QQuickText::ProportionalHeight);
2022 myText->setLineHeight(1.0);
2024 qreal h2 = myText->height();
2025 myText->setLineHeight(2.0);
2026 QVERIFY(myText->height() == h2 * 2.0);
2028 myText->setLineHeightMode(QQuickText::FixedHeight);
2029 myText->setLineHeight(10);
2030 QCOMPARE(myText->height(), myText->lineCount() * 10.0);
2035 void tst_qquicktext::implicitSize_data()
2037 QTest::addColumn<QString>("text");
2038 QTest::addColumn<QString>("width");
2039 QTest::addColumn<QString>("wrap");
2040 QTest::addColumn<QString>("elide");
2041 QTest::addColumn<QString>("format");
2042 QTest::newRow("plain") << "The quick red fox jumped over the lazy brown dog" << "50" << "Text.NoWrap" << "Text.ElideNone" << "Text.PlainText";
2043 QTest::newRow("richtext") << "<b>The quick red fox jumped over the lazy brown dog</b>" <<" 50" << "Text.NoWrap" << "Text.ElideNone" << "Text.RichText";
2044 QTest::newRow("styledtext") << "<b>The quick red fox jumped over the lazy brown dog</b>" <<" 50" << "Text.NoWrap" << "Text.ElideNone" << "Text.StyledText";
2045 QTest::newRow("plain, 0 width") << "The quick red fox jumped over the lazy brown dog" << "0" << "Text.NoWrap" << "Text.ElideNone" << "Text.PlainText";
2046 QTest::newRow("plain, elide") << "The quick red fox jumped over the lazy brown dog" << "50" << "Text.NoWrap" << "Text.ElideRight" << "Text.PlainText";
2047 QTest::newRow("plain, 0 width, elide") << "The quick red fox jumped over the lazy brown dog" << "0" << "Text.NoWrap" << "Text.ElideRight" << "Text.PlainText";
2048 QTest::newRow("richtext, 0 width") << "<b>The quick red fox jumped over the lazy brown dog</b>" <<" 0" << "Text.NoWrap" << "Text.ElideNone" << "Text.RichText";
2049 QTest::newRow("styledtext, 0 width") << "<b>The quick red fox jumped over the lazy brown dog</b>" <<" 0" << "Text.NoWrap" << "Text.ElideNone" << "Text.StyledText";
2050 QTest::newRow("plain_wrap") << "The quick red fox jumped over the lazy brown dog" << "50" << "Text.Wrap" << "Text.ElideNone" << "Text.PlainText";
2051 QTest::newRow("richtext_wrap") << "<b>The quick red fox jumped over the lazy brown dog</b>" << "50" << "Text.Wrap" << "Text.ElideNone" << "Text.RichText";
2052 QTest::newRow("styledtext_wrap") << "<b>The quick red fox jumped over the lazy brown dog</b>" << "50" << "Text.Wrap" << "Text.ElideNone" << "Text.StyledText";
2053 QTest::newRow("plain_wrap, 0 width") << "The quick red fox jumped over the lazy brown dog" << "0" << "Text.Wrap" << "Text.ElideNone" << "Text.PlainText";
2054 QTest::newRow("plain_wrap, elide") << "The quick red fox jumped over the lazy brown dog" << "50" << "Text.Wrap" << "Text.ElideRight" << "Text.PlainText";
2055 QTest::newRow("plain_wrap, 0 width, elide") << "The quick red fox jumped over the lazy brown dog" << "0" << "Text.Wrap" << "Text.ElideRight" << "Text.PlainText";
2056 QTest::newRow("richtext_wrap, 0 width") << "<b>The quick red fox jumped over the lazy brown dog</b>" << "0" << "Text.Wrap" << "Text.ElideNone" << "Text.RichText";
2057 QTest::newRow("styledtext_wrap, 0 width") << "<b>The quick red fox jumped over the lazy brown dog</b>" << "0" << "Text.Wrap" << "Text.ElideNone" << "Text.StyledText";
2060 void tst_qquicktext::implicitSize()
2062 QFETCH(QString, text);
2063 QFETCH(QString, width);
2064 QFETCH(QString, format);
2065 QFETCH(QString, wrap);
2066 QFETCH(QString, elide);
2067 QString componentStr = "import QtQuick 2.0\nText { "
2068 "property real iWidth: implicitWidth; "
2069 "text: \"" + text + "\"; "
2070 "width: " + width + "; "
2071 "textFormat: " + format + "; "
2072 "wrapMode: " + wrap + "; "
2073 "elide: " + elide + "; "
2074 "maximumLineCount: 2 }";
2075 QQmlComponent textComponent(&engine);
2076 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
2077 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
2079 QVERIFY(textObject->width() < textObject->implicitWidth());
2080 QVERIFY(textObject->height() == textObject->implicitHeight());
2081 QCOMPARE(textObject->property("iWidth").toReal(), textObject->implicitWidth());
2083 textObject->resetWidth();
2084 QVERIFY(textObject->width() == textObject->implicitWidth());
2085 QVERIFY(textObject->height() == textObject->implicitHeight());
2090 void tst_qquicktext::contentSize()
2092 QString componentStr = "import QtQuick 2.0\nText { width: 75; height: 16; font.pixelSize: 10 }";
2093 QQmlComponent textComponent(&engine);
2094 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
2095 QScopedPointer<QObject> object(textComponent.create());
2096 QQuickText *textObject = qobject_cast<QQuickText *>(object.data());
2098 QSignalSpy spy(textObject, SIGNAL(contentSizeChanged()));
2100 textObject->setText("The quick red fox jumped over the lazy brown dog");
2102 QVERIFY(textObject->contentWidth() > textObject->width());
2103 QVERIFY(textObject->contentHeight() < textObject->height());
2104 QCOMPARE(spy.count(), 1);
2106 textObject->setWrapMode(QQuickText::WordWrap);
2107 QVERIFY(textObject->contentWidth() <= textObject->width());
2108 QVERIFY(textObject->contentHeight() > textObject->height());
2109 QCOMPARE(spy.count(), 2);
2111 textObject->setElideMode(QQuickText::ElideRight);
2112 QVERIFY(textObject->contentWidth() <= textObject->width());
2113 QVERIFY(textObject->contentHeight() < textObject->height());
2114 QCOMPARE(spy.count(), 3);
2116 qreal elidedWidth = textObject->contentWidth();
2118 textObject->setText("The quickredfoxjumpedoverthe lazy brown dog");
2119 QVERIFY(textObject->contentWidth() <= textObject->width());
2120 QVERIFY(textObject->contentHeight() < textObject->height());
2121 // this text probably won't have the same elided width, but it's not guaranteed.
2122 if (textObject->contentWidth() != elidedWidth)
2123 QCOMPARE(spy.count(), ++spyCount);
2125 QCOMPARE(spy.count(), spyCount);
2127 textObject->setElideMode(QQuickText::ElideNone);
2128 QVERIFY(textObject->contentWidth() > textObject->width());
2129 QVERIFY(textObject->contentHeight() > textObject->height());
2130 QCOMPARE(spy.count(), ++spyCount);
2133 void tst_qquicktext::geometryChanged()
2135 // Test that text is re-laid out when the geometry of the item by verifying changes in content
2136 // size. Implicit width is also tested as that in combination with item geometry provides a
2137 // reference for expected content sizes.
2139 QString componentStr = "import QtQuick 2.0\nText { font.family: \"__Qt__Box__Engine__\"; font.pixelSize: 10 }";
2140 QQmlComponent textComponent(&engine);
2141 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
2142 QScopedPointer<QObject> object(textComponent.create());
2143 QQuickText *textObject = qobject_cast<QQuickText *>(object.data());
2145 const qreal implicitHeight = textObject->implicitHeight();
2147 const qreal widths[] = { 100, 2000, 3000, -100, 100 };
2148 const qreal heights[] = { implicitHeight, 2000, 3000, -implicitHeight, implicitHeight };
2150 QCOMPARE(textObject->implicitWidth(), 0.);
2151 QVERIFY(implicitHeight > 0.);
2152 QCOMPARE(textObject->width(), textObject->implicitWidth());
2153 QCOMPARE(textObject->height(), implicitHeight);
2154 QCOMPARE(textObject->contentWidth(), textObject->implicitWidth());
2155 QCOMPARE(textObject->contentHeight(), implicitHeight);
2157 textObject->setText("The quick red fox jumped over the lazy brown dog");
2159 const qreal implicitWidth = textObject->implicitWidth();
2161 QVERIFY(implicitWidth > 0.);
2162 QCOMPARE(textObject->implicitHeight(), implicitHeight);
2163 QCOMPARE(textObject->width(), textObject->implicitWidth());
2164 QCOMPARE(textObject->height(), textObject->implicitHeight());
2165 QCOMPARE(textObject->contentWidth(), textObject->implicitWidth());
2166 QCOMPARE(textObject->contentHeight(), textObject->implicitHeight());
2168 // Changing the geometry with no eliding, or wrapping doesn't change the content size.
2169 for (int i = 0; i < 5; ++i) {
2170 textObject->setWidth(widths[i]);
2171 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2172 QCOMPARE(textObject->implicitHeight(), implicitHeight);
2173 QCOMPARE(textObject->width(), widths[i]);
2174 QCOMPARE(textObject->height(), implicitHeight);
2175 QCOMPARE(textObject->contentWidth(), implicitWidth);
2176 QCOMPARE(textObject->contentHeight(), implicitHeight);
2179 // With eliding enabled the content width is bounded to the item width, but is never
2180 // larger than the implicit width.
2181 textObject->setElideMode(QQuickText::ElideRight);
2182 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2183 QCOMPARE(textObject->implicitHeight(), implicitHeight);
2184 QCOMPARE(textObject->width(), 100.);
2185 QCOMPARE(textObject->height(), implicitHeight);
2186 QVERIFY(textObject->contentWidth() <= 100.);
2187 QCOMPARE(textObject->contentHeight(), implicitHeight);
2189 textObject->setWidth(2000.);
2190 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2191 QCOMPARE(textObject->implicitHeight(), implicitHeight);
2192 QCOMPARE(textObject->width(), 2000.);
2193 QCOMPARE(textObject->height(), implicitHeight);
2194 QCOMPARE(textObject->contentWidth(), implicitWidth);
2195 QCOMPARE(textObject->contentHeight(), implicitHeight);
2197 textObject->setWidth(3000.);
2198 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2199 QCOMPARE(textObject->implicitHeight(), implicitHeight);
2200 QCOMPARE(textObject->width(), 3000.);
2201 QCOMPARE(textObject->height(), implicitHeight);
2202 QCOMPARE(textObject->contentWidth(), implicitWidth);
2203 QCOMPARE(textObject->contentHeight(), implicitHeight);
2205 textObject->setWidth(-100);
2206 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2207 QCOMPARE(textObject->implicitHeight(), implicitHeight);
2208 QCOMPARE(textObject->width(), -100.);
2209 QCOMPARE(textObject->height(), implicitHeight);
2210 QCOMPARE(textObject->contentWidth(), 0.);
2211 QCOMPARE(textObject->contentHeight(), implicitHeight);
2213 textObject->setWidth(100.);
2214 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2215 QCOMPARE(textObject->implicitHeight(), implicitHeight);
2216 QCOMPARE(textObject->width(), 100.);
2217 QCOMPARE(textObject->height(), implicitHeight);
2218 QVERIFY(textObject->contentWidth() <= 100.);
2219 QCOMPARE(textObject->contentHeight(), implicitHeight);
2221 // With wrapping enabled the implicit height changes with the width.
2222 textObject->setElideMode(QQuickText::ElideNone);
2223 textObject->setWrapMode(QQuickText::Wrap);
2224 const qreal wrappedImplicitHeight = textObject->implicitHeight();
2226 QVERIFY(wrappedImplicitHeight > implicitHeight);
2228 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2229 QCOMPARE(textObject->width(), 100.);
2230 QCOMPARE(textObject->height(), wrappedImplicitHeight);
2231 QVERIFY(textObject->contentWidth() <= 100.);
2232 QCOMPARE(textObject->contentHeight(), wrappedImplicitHeight);
2234 textObject->setWidth(2000.);
2235 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2236 QCOMPARE(textObject->implicitHeight(), implicitHeight);
2237 QCOMPARE(textObject->width(), 2000.);
2238 QCOMPARE(textObject->height(), implicitHeight);
2239 QCOMPARE(textObject->contentWidth(), implicitWidth);
2240 QCOMPARE(textObject->contentHeight(), implicitHeight);
2242 textObject->setWidth(3000.);
2243 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2244 QCOMPARE(textObject->implicitHeight(), implicitHeight);
2245 QCOMPARE(textObject->width(), 3000.);
2246 QCOMPARE(textObject->height(), implicitHeight);
2247 QCOMPARE(textObject->contentWidth(), implicitWidth);
2248 QCOMPARE(textObject->contentHeight(), implicitHeight);
2250 textObject->setWidth(-100);
2251 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2252 QCOMPARE(textObject->implicitHeight(), implicitHeight);
2253 QCOMPARE(textObject->width(), -100.);
2254 QCOMPARE(textObject->height(), implicitHeight);
2255 QCOMPARE(textObject->contentWidth(), implicitWidth); // 0 or negative width item won't wrap.
2256 QCOMPARE(textObject->contentHeight(), implicitHeight);
2258 textObject->setWidth(100.);
2259 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2260 QCOMPARE(textObject->implicitHeight(), wrappedImplicitHeight);
2261 QCOMPARE(textObject->width(), 100.);
2262 QCOMPARE(textObject->height(), wrappedImplicitHeight);
2263 QVERIFY(textObject->contentWidth() <= 100.);
2264 QCOMPARE(textObject->contentHeight(), wrappedImplicitHeight);
2266 // With no eliding or maximum line count the content height is the same as the implicit height.
2267 for (int i = 0; i < 5; ++i) {
2268 textObject->setHeight(heights[i]);
2269 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2270 QCOMPARE(textObject->implicitHeight(), wrappedImplicitHeight);
2271 QCOMPARE(textObject->width(), 100.);
2272 QCOMPARE(textObject->height(), heights[i]);
2273 QVERIFY(textObject->contentWidth() <= 100.);
2274 QCOMPARE(textObject->contentHeight(), wrappedImplicitHeight);
2277 // The implicit height is unaffected by eliding but the content height will change.
2278 textObject->setElideMode(QQuickText::ElideRight);
2280 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2281 QCOMPARE(textObject->implicitHeight(), wrappedImplicitHeight);
2282 QCOMPARE(textObject->width(), 100.);
2283 QCOMPARE(textObject->height(), implicitHeight);
2284 QVERIFY(textObject->contentWidth() <= 100.);
2285 QCOMPARE(textObject->contentHeight(), implicitHeight);
2287 textObject->setHeight(2000);
2288 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2289 QCOMPARE(textObject->implicitHeight(), wrappedImplicitHeight);
2290 QCOMPARE(textObject->width(), 100.);
2291 QCOMPARE(textObject->height(), 2000.);
2292 QVERIFY(textObject->contentWidth() <= 100.);
2293 QCOMPARE(textObject->contentHeight(), wrappedImplicitHeight);
2295 textObject->setHeight(3000);
2296 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2297 QCOMPARE(textObject->implicitHeight(), wrappedImplicitHeight);
2298 QCOMPARE(textObject->width(), 100.);
2299 QCOMPARE(textObject->height(), 3000.);
2300 QVERIFY(textObject->contentWidth() <= 100.);
2301 QCOMPARE(textObject->contentHeight(), wrappedImplicitHeight);
2303 textObject->setHeight(-implicitHeight);
2304 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2305 QCOMPARE(textObject->implicitHeight(), wrappedImplicitHeight);
2306 QCOMPARE(textObject->width(), 100.);
2307 QCOMPARE(textObject->height(), -implicitHeight);
2308 QVERIFY(textObject->contentWidth() <= 0.);
2309 QCOMPARE(textObject->contentHeight(), implicitHeight); // content height is never less than font height. seems a little odd in this instance.
2311 textObject->setHeight(implicitHeight);
2312 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2313 QCOMPARE(textObject->implicitHeight(), wrappedImplicitHeight);
2314 QCOMPARE(textObject->width(), 100.);
2315 QCOMPARE(textObject->height(), implicitHeight);
2316 QVERIFY(textObject->contentWidth() <= 100.);
2317 QCOMPARE(textObject->contentHeight(), implicitHeight);
2319 // Varying the height with a maximum line count but no eliding won't affect the content height.
2320 textObject->setElideMode(QQuickText::ElideNone);
2321 textObject->setMaximumLineCount(2);
2322 textObject->resetHeight();
2324 const qreal maxLineCountImplicitHeight = textObject->implicitHeight();
2325 QVERIFY(maxLineCountImplicitHeight > implicitHeight);
2326 QVERIFY(maxLineCountImplicitHeight < wrappedImplicitHeight);
2328 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2329 QCOMPARE(textObject->width(), 100.);
2330 QCOMPARE(textObject->height(), maxLineCountImplicitHeight);
2331 QVERIFY(textObject->contentWidth() <= 100.);
2332 QCOMPARE(textObject->contentHeight(), maxLineCountImplicitHeight);
2334 for (int i = 0; i < 5; ++i) {
2335 textObject->setHeight(heights[i]);
2336 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2337 QCOMPARE(textObject->implicitHeight(), maxLineCountImplicitHeight);
2338 QCOMPARE(textObject->width(), 100.);
2339 QCOMPARE(textObject->height(), heights[i]);
2340 QVERIFY(textObject->contentWidth() <= 100.);
2341 QCOMPARE(textObject->contentHeight(), maxLineCountImplicitHeight);
2344 // Varying the width with a maximum line count won't increase the implicit height beyond the
2345 // height of the maximum number of lines.
2346 textObject->setWidth(2000.);
2347 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2348 QCOMPARE(textObject->implicitHeight(), implicitHeight);
2349 QCOMPARE(textObject->width(), 2000.);
2350 QCOMPARE(textObject->height(), implicitHeight);
2351 QCOMPARE(textObject->contentWidth(), implicitWidth);
2352 QCOMPARE(textObject->contentHeight(), implicitHeight);
2354 textObject->setWidth(3000.);
2355 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2356 QCOMPARE(textObject->implicitHeight(), implicitHeight);
2357 QCOMPARE(textObject->width(), 3000.);
2358 QCOMPARE(textObject->height(), implicitHeight);
2359 QCOMPARE(textObject->contentWidth(), implicitWidth);
2360 QCOMPARE(textObject->contentHeight(), implicitHeight);
2362 textObject->setWidth(-100);
2363 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2364 QCOMPARE(textObject->implicitHeight(), implicitHeight);
2365 QCOMPARE(textObject->width(), -100.);
2366 QCOMPARE(textObject->height(), implicitHeight);
2367 QCOMPARE(textObject->contentWidth(), implicitWidth); // 0 or negative width item won't wrap.
2368 QCOMPARE(textObject->contentHeight(), implicitHeight);
2370 textObject->setWidth(50.);
2371 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2372 QCOMPARE(textObject->implicitHeight(), maxLineCountImplicitHeight);
2373 QCOMPARE(textObject->width(), 50.);
2374 QCOMPARE(textObject->height(), implicitHeight);
2375 QVERIFY(textObject->contentWidth() <= 50.);
2376 QCOMPARE(textObject->contentHeight(), maxLineCountImplicitHeight);
2378 textObject->setWidth(100.);
2379 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2380 QCOMPARE(textObject->implicitHeight(), maxLineCountImplicitHeight);
2381 QCOMPARE(textObject->width(), 100.);
2382 QCOMPARE(textObject->height(), implicitHeight);
2383 QVERIFY(textObject->contentWidth() <= 100.);
2384 QCOMPARE(textObject->contentHeight(), maxLineCountImplicitHeight);
2387 void tst_qquicktext::implicitSizeBinding_data()
2389 implicitSize_data();
2392 void tst_qquicktext::implicitSizeBinding()
2394 QFETCH(QString, text);
2395 QFETCH(QString, wrap);
2396 QFETCH(QString, format);
2397 QString componentStr = "import QtQuick 2.0\nText { text: \"" + text + "\"; width: implicitWidth; height: implicitHeight; wrapMode: " + wrap + "; textFormat: " + format + " }";
2399 QQmlComponent textComponent(&engine);
2400 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
2401 QScopedPointer<QObject> object(textComponent.create());
2402 QQuickText *textObject = qobject_cast<QQuickText *>(object.data());
2404 QCOMPARE(textObject->width(), textObject->implicitWidth());
2405 QCOMPARE(textObject->height(), textObject->implicitHeight());
2407 textObject->resetWidth();
2408 QCOMPARE(textObject->width(), textObject->implicitWidth());
2409 QCOMPARE(textObject->height(), textObject->implicitHeight());
2411 textObject->resetHeight();
2412 QCOMPARE(textObject->width(), textObject->implicitWidth());
2413 QCOMPARE(textObject->height(), textObject->implicitHeight());
2416 void tst_qquicktext::boundingRect_data()
2418 QTest::addColumn<QString>("format");
2419 QTest::newRow("PlainText") << "Text.PlainText";
2420 QTest::newRow("StyledText") << "Text.StyledText";
2421 QTest::newRow("RichText") << "Text.RichText";
2424 void tst_qquicktext::boundingRect()
2426 QFETCH(QString, format);
2428 QQmlComponent component(&engine);
2429 component.setData("import QtQuick 2.0\n Text { textFormat:" + format.toUtf8() + "}", QUrl());
2430 QScopedPointer<QObject> object(component.create());
2431 QQuickText *text = qobject_cast<QQuickText *>(object.data());
2434 QCOMPARE(text->boundingRect().x(), qreal(0));
2435 QCOMPARE(text->boundingRect().y(), qreal(0));
2436 QCOMPARE(text->boundingRect().width(), qreal(0));
2437 QCOMPARE(text->boundingRect().height(), qreal(qCeil(QFontMetricsF(text->font()).height())));
2439 text->setText("Hello World");
2441 QTextLayout layout(text->text());
2442 layout.setFont(text->font());
2444 if (!qmlDisableDistanceField()) {
2446 option.setUseDesignMetrics(true);
2447 layout.setTextOption(option);
2449 layout.beginLayout();
2450 QTextLine line = layout.createLine();
2453 QCOMPARE(text->boundingRect().x(), qreal(0));
2454 QCOMPARE(text->boundingRect().y(), qreal(0));
2455 QCOMPARE(text->boundingRect().width(), line.naturalTextWidth());
2456 QCOMPARE(text->boundingRect().height(), line.height());
2458 // the size of the bounding rect shouldn't be bounded by the size of item.
2459 text->setWidth(text->width() / 2);
2460 QCOMPARE(text->boundingRect().x(), qreal(0));
2461 QCOMPARE(text->boundingRect().y(), qreal(0));
2462 QCOMPARE(text->boundingRect().width(), line.naturalTextWidth());
2463 QCOMPARE(text->boundingRect().height(), line.height());
2465 text->setHeight(text->height() * 2);
2466 QCOMPARE(text->boundingRect().x(), qreal(0));
2467 QCOMPARE(text->boundingRect().y(), qreal(0));
2468 QCOMPARE(text->boundingRect().width(), line.naturalTextWidth());
2469 QCOMPARE(text->boundingRect().height(), line.height());
2471 text->setHAlign(QQuickText::AlignRight);
2472 QCOMPARE(text->boundingRect().x(), text->width() - line.naturalTextWidth());
2473 QCOMPARE(text->boundingRect().y(), qreal(0));
2474 QCOMPARE(text->boundingRect().width(), line.naturalTextWidth());
2475 QCOMPARE(text->boundingRect().height(), line.height());
2477 text->setWrapMode(QQuickText::Wrap);
2478 QCOMPARE(text->boundingRect().right(), text->width());
2479 QCOMPARE(text->boundingRect().y(), qreal(0));
2480 QVERIFY(text->boundingRect().width() < line.naturalTextWidth());
2481 QVERIFY(text->boundingRect().height() > line.height());
2483 text->setVAlign(QQuickText::AlignBottom);
2484 QCOMPARE(text->boundingRect().right(), text->width());
2485 QCOMPARE(text->boundingRect().bottom(), text->height());
2486 QVERIFY(text->boundingRect().width() < line.naturalTextWidth());
2487 QVERIFY(text->boundingRect().height() > line.height());
2490 void tst_qquicktext::clipRect()
2492 QQmlComponent component(&engine);
2493 component.setData("import QtQuick 2.0\n Text {}", QUrl());
2494 QScopedPointer<QObject> object(component.create());
2495 QQuickText *text = qobject_cast<QQuickText *>(object.data());
2499 layout.setFont(text->font());
2501 QCOMPARE(text->clipRect().x(), qreal(0));
2502 QCOMPARE(text->clipRect().y(), qreal(0));
2503 QCOMPARE(text->clipRect().width(), text->width());
2504 QCOMPARE(text->clipRect().height(), text->height());
2506 text->setText("Hello World");
2508 QCOMPARE(text->clipRect().x(), qreal(0));
2509 QCOMPARE(text->clipRect().y(), qreal(0));
2510 QCOMPARE(text->clipRect().width(), text->width());
2511 QCOMPARE(text->clipRect().height(), text->height());
2513 // Clip rect follows the item not content dimensions.
2514 text->setWidth(text->width() / 2);
2515 QCOMPARE(text->clipRect().x(), qreal(0));
2516 QCOMPARE(text->clipRect().y(), qreal(0));
2517 QCOMPARE(text->clipRect().width(), text->width());
2518 QCOMPARE(text->clipRect().height(), text->height());
2520 text->setHeight(text->height() * 2);
2521 QCOMPARE(text->clipRect().x(), qreal(0));
2522 QCOMPARE(text->clipRect().y(), qreal(0));
2523 QCOMPARE(text->clipRect().width(), text->width());
2524 QCOMPARE(text->clipRect().height(), text->height());
2526 // Setting a style adds a small amount of padding to the clip rect.
2527 text->setStyle(QQuickText::Outline);
2528 QCOMPARE(text->clipRect().x(), qreal(-1));
2529 QCOMPARE(text->clipRect().y(), qreal(0));
2530 QCOMPARE(text->clipRect().width(), text->width() + 2);
2531 QCOMPARE(text->clipRect().height(), text->height() + 2);
2534 void tst_qquicktext::lineLaidOut()
2536 QQuickView *window = createView(testFile("lineLayout.qml"));
2538 QQuickText *myText = window->rootObject()->findChild<QQuickText*>("myText");
2539 QVERIFY(myText != 0);
2541 QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(myText);
2542 QVERIFY(textPrivate != 0);
2544 QVERIFY(!textPrivate->extra.isAllocated());
2546 for (int i = 0; i < textPrivate->layout.lineCount(); ++i) {
2547 QRectF r = textPrivate->layout.lineAt(i).rect();
2548 QVERIFY(r.width() == i * 15);
2550 QVERIFY(r.x() == r.width() + 30);
2552 QVERIFY(r.x() == r.width() * 2 + 60);
2553 QVERIFY(r.height() == 20);
2560 void tst_qquicktext::lineLaidOutRelayout()
2562 QQuickView *window = createView(testFile("lineLayoutRelayout.qml"));
2565 window->requestActivateWindow();
2566 QVERIFY(QTest::qWaitForWindowActive(window));
2568 QQuickText *myText = window->rootObject()->findChild<QQuickText*>("myText");
2569 QVERIFY(myText != 0);
2571 QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(myText);
2572 QVERIFY(textPrivate != 0);
2574 QVERIFY(!textPrivate->extra.isAllocated());
2577 for (int i = 0; i < textPrivate->layout.lineCount(); ++i) {
2578 QRectF r = textPrivate->layout.lineAt(i).rect();
2581 QCOMPARE(r.y(), i * r.height());
2582 maxH = qMax(maxH, r.y() + r.height());
2584 QCOMPARE(r.x(), myText->width() / 2);
2585 QCOMPARE(r.y(), (i * r.height()) - maxH);
2592 void tst_qquicktext::imgTagsBaseUrl_data()
2594 QTest::addColumn<QUrl>("src");
2595 QTest::addColumn<QUrl>("baseUrl");
2596 QTest::addColumn<QUrl>("contextUrl");
2597 QTest::addColumn<qreal>("imgHeight");
2599 QTest::newRow("absolute local")
2600 << testFileUrl("images/heart200.png")
2604 QTest::newRow("relative local context 1")
2605 << QUrl("images/heart200.png")
2607 << testFileUrl("/app.qml")
2609 QTest::newRow("relative local context 2")
2610 << QUrl("heart200.png")
2612 << testFileUrl("images/app.qml")
2614 QTest::newRow("relative local base 1")
2615 << QUrl("images/heart200.png")
2617 << testFileUrl("nonexistant/app.qml")
2619 QTest::newRow("relative local base 2")
2620 << QUrl("heart200.png")
2621 << testFileUrl("images/")
2622 << testFileUrl("nonexistant/app.qml")
2624 QTest::newRow("base relative to local context")
2625 << QUrl("heart200.png")
2626 << testFileUrl("images/")
2627 << testFileUrl("/app.qml")
2630 QTest::newRow("absolute remote")
2631 << QUrl(SERVER_ADDR "/images/heart200.png")
2635 QTest::newRow("relative remote base 1")
2636 << QUrl("images/heart200.png")
2637 << QUrl(SERVER_ADDR "/")
2638 << testFileUrl("nonexistant/app.qml")
2640 QTest::newRow("relative remote base 2")
2641 << QUrl("heart200.png")
2642 << QUrl(SERVER_ADDR "/images/")
2643 << testFileUrl("nonexistant/app.qml")
2647 void tst_qquicktext::imgTagsBaseUrl()
2650 QFETCH(QUrl, baseUrl);
2651 QFETCH(QUrl, contextUrl);
2652 QFETCH(qreal, imgHeight);
2654 TestHTTPServer server(SERVER_PORT);
2655 server.serveDirectory(testFile(""));
2657 QByteArray baseUrlFragment;
2658 if (!baseUrl.isEmpty())
2659 baseUrlFragment = "; baseUrl: \"" + baseUrl.toEncoded() + "\"";
2660 QByteArray componentStr = "import QtQuick 2.0\nText { text: \"This is a test <img src=\\\"" + src.toEncoded() + "\\\">\"" + baseUrlFragment + " }";
2662 QQmlComponent component(&engine);
2663 component.setData(componentStr, contextUrl);
2664 QScopedPointer<QObject> object(component.create());
2665 QQuickText *textObject = qobject_cast<QQuickText *>(object.data());
2666 QVERIFY(textObject);
2668 QCoreApplication::processEvents();
2670 QTRY_COMPARE(textObject->height(), imgHeight);
2673 void tst_qquicktext::imgTagsAlign_data()
2675 QTest::addColumn<QString>("src");
2676 QTest::addColumn<int>("imgHeight");
2677 QTest::addColumn<QString>("align");
2678 QTest::newRow("heart-bottom") << "data/images/heart200.png" << 181 << "bottom";
2679 QTest::newRow("heart-middle") << "data/images/heart200.png" << 181 << "middle";
2680 QTest::newRow("heart-top") << "data/images/heart200.png" << 181 << "top";
2681 QTest::newRow("starfish-bottom") << "data/images/starfish_2.png" << 217 << "bottom";
2682 QTest::newRow("starfish-middle") << "data/images/starfish_2.png" << 217 << "middle";
2683 QTest::newRow("starfish-top") << "data/images/starfish_2.png" << 217 << "top";
2686 void tst_qquicktext::imgTagsAlign()
2688 QFETCH(QString, src);
2689 QFETCH(int, imgHeight);
2690 QFETCH(QString, align);
2691 QString componentStr = "import QtQuick 2.0\nText { text: \"This is a test <img src=\\\"" + src + "\\\" align=\\\"" + align + "\\\"> of image.\" }";
2692 QQmlComponent textComponent(&engine);
2693 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
2694 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
2696 QVERIFY(textObject != 0);
2697 QVERIFY(textObject->height() == imgHeight);
2699 QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject);
2700 QVERIFY(textPrivate != 0);
2702 QRectF br = textPrivate->layout.boundingRect();
2703 if (align == "bottom")
2704 QVERIFY(br.y() == imgHeight - br.height());
2705 else if (align == "middle")
2706 QVERIFY(br.y() == imgHeight / 2.0 - br.height() / 2.0);
2707 else if (align == "top")
2708 QVERIFY(br.y() == 0);
2713 void tst_qquicktext::imgTagsMultipleImages()
2715 QString componentStr = "import QtQuick 2.0\nText { text: \"This is a starfish<img src=\\\"data/images/starfish_2.png\\\" width=\\\"60\\\" height=\\\"60\\\" > and another one<img src=\\\"data/images/heart200.png\\\" width=\\\"85\\\" height=\\\"85\\\">.\" }";
2717 QQmlComponent textComponent(&engine);
2718 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
2719 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
2721 QVERIFY(textObject != 0);
2722 QVERIFY(textObject->height() == 85);
2724 QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject);
2725 QVERIFY(textPrivate != 0);
2726 QVERIFY(textPrivate->visibleImgTags.count() == 2);
2731 void tst_qquicktext::imgTagsElide()
2733 QQuickView *window = createView(testFile("imgTagsElide.qml"));
2734 QQuickText *myText = window->rootObject()->findChild<QQuickText*>("myText");
2735 QVERIFY(myText != 0);
2737 QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(myText);
2738 QVERIFY(textPrivate != 0);
2739 QVERIFY(textPrivate->visibleImgTags.count() == 0);
2740 myText->setMaximumLineCount(20);
2741 QTRY_VERIFY(textPrivate->visibleImgTags.count() == 1);
2747 void tst_qquicktext::imgTagsUpdates()
2749 QQuickView *window = createView(testFile("imgTagsUpdates.qml"));
2750 QQuickText *myText = window->rootObject()->findChild<QQuickText*>("myText");
2751 QVERIFY(myText != 0);
2753 QSignalSpy spy(myText, SIGNAL(contentSizeChanged()));
2755 QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(myText);
2756 QVERIFY(textPrivate != 0);
2758 myText->setText("This is a heart<img src=\"images/heart200.png\">.");
2759 QVERIFY(textPrivate->visibleImgTags.count() == 1);
2760 QVERIFY(spy.count() == 1);
2762 myText->setMaximumLineCount(2);
2763 myText->setText("This is another heart<img src=\"images/heart200.png\">.");
2764 QTRY_VERIFY(textPrivate->visibleImgTags.count() == 1);
2766 // if maximumLineCount is set and the img tag doesn't have an explicit size
2767 // we relayout twice.
2768 QVERIFY(spy.count() == 3);
2774 void tst_qquicktext::imgTagsError()
2776 QString componentStr = "import QtQuick 2.0\nText { text: \"This is a starfish<img src=\\\"data/images/starfish_2.pn\\\" width=\\\"60\\\" height=\\\"60\\\">.\" }";
2778 QQmlComponent textComponent(&engine);
2779 QTest::ignoreMessage(QtWarningMsg, "file::2:1: QML Text: Cannot open: file:data/images/starfish_2.pn");
2780 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
2781 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
2783 QVERIFY(textObject != 0);
2787 void tst_qquicktext::fontSizeMode_data()
2789 QTest::addColumn<QString>("text");
2790 QTest::newRow("plain") << "The quick red fox jumped over the lazy brown dog";
2791 QTest::newRow("styled") << "<b>The quick red fox jumped over the lazy brown dog</b>";
2794 void tst_qquicktext::fontSizeMode()
2796 QFETCH(QString, text);
2798 QScopedPointer<QQuickView> window(createView(testFile("fontSizeMode.qml")));
2801 QQuickText *myText = window->rootObject()->findChild<QQuickText*>("myText");
2802 QVERIFY(myText != 0);
2804 myText->setText(text);
2805 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2807 qreal originalWidth = myText->contentWidth();
2808 qreal originalHeight = myText->contentHeight();
2810 // The original text unwrapped should exceed the width of the item.
2811 QVERIFY(originalWidth > myText->width());
2812 QVERIFY(originalHeight < myText->height());
2814 QFont font = myText->font();
2815 font.setPixelSize(64);
2817 myText->setFont(font);
2818 myText->setFontSizeMode(QQuickText::HorizontalFit);
2819 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2820 // Font size reduced to fit within the width of the item.
2821 qreal horizontalFitWidth = myText->contentWidth();
2822 qreal horizontalFitHeight = myText->contentHeight();
2823 QVERIFY(horizontalFitWidth <= myText->width() + 2); // rounding
2824 QVERIFY(horizontalFitHeight <= myText->height() + 2);
2826 // Elide won't affect the size with HorizontalFit.
2827 myText->setElideMode(QQuickText::ElideRight);
2828 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2829 QVERIFY(!myText->truncated());
2830 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2831 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2833 myText->setElideMode(QQuickText::ElideLeft);
2834 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2835 QVERIFY(!myText->truncated());
2836 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2837 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2839 myText->setElideMode(QQuickText::ElideMiddle);
2840 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2841 QVERIFY(!myText->truncated());
2842 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2843 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2845 myText->setElideMode(QQuickText::ElideNone);
2846 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2848 myText->setFontSizeMode(QQuickText::VerticalFit);
2849 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2850 // Font size increased to fill the height of the item.
2851 qreal verticalFitHeight = myText->contentHeight();
2852 QVERIFY(myText->contentWidth() > myText->width());
2853 QVERIFY(verticalFitHeight <= myText->height() + 2);
2854 QVERIFY(verticalFitHeight > originalHeight);
2856 // Elide won't affect the height of a single line with VerticalFit but will crop the width.
2857 myText->setElideMode(QQuickText::ElideRight);
2858 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2859 QVERIFY(myText->truncated());
2860 QVERIFY(myText->contentWidth() <= myText->width() + 2);
2861 QCOMPARE(myText->contentHeight(), verticalFitHeight);
2863 myText->setElideMode(QQuickText::ElideLeft);
2864 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2865 QVERIFY(myText->truncated());
2866 QVERIFY(myText->contentWidth() <= myText->width() + 2);
2867 QCOMPARE(myText->contentHeight(), verticalFitHeight);
2869 myText->setElideMode(QQuickText::ElideMiddle);
2870 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2871 QVERIFY(myText->truncated());
2872 QVERIFY(myText->contentWidth() <= myText->width() + 2);
2873 QCOMPARE(myText->contentHeight(), verticalFitHeight);
2875 myText->setElideMode(QQuickText::ElideNone);
2876 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2878 myText->setFontSizeMode(QQuickText::Fit);
2879 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2880 // Should be the same as HorizontalFit with no wrapping.
2881 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2882 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2884 // Elide won't affect the size with Fit.
2885 myText->setElideMode(QQuickText::ElideRight);
2886 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2887 QVERIFY(!myText->truncated());
2888 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2889 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2891 myText->setElideMode(QQuickText::ElideLeft);
2892 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2893 QVERIFY(!myText->truncated());
2894 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2895 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2897 myText->setElideMode(QQuickText::ElideMiddle);
2898 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2899 QVERIFY(!myText->truncated());
2900 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2901 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2903 myText->setElideMode(QQuickText::ElideNone);
2904 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2906 myText->setFontSizeMode(QQuickText::FixedSize);
2907 myText->setWrapMode(QQuickText::Wrap);
2908 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2910 originalWidth = myText->contentWidth();
2911 originalHeight = myText->contentHeight();
2913 // The original text wrapped should exceed the height of the item.
2914 QVERIFY(originalWidth <= myText->width() + 2);
2915 QVERIFY(originalHeight > myText->height());
2917 myText->setFontSizeMode(QQuickText::HorizontalFit);
2918 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2919 // HorizontalFit should reduce the font size to minimize wrapping, which brings it back to the
2920 // same size as without text wrapping.
2921 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2922 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2924 // Elide won't affect the size with HorizontalFit.
2925 myText->setElideMode(QQuickText::ElideRight);
2926 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2927 QVERIFY(!myText->truncated());
2928 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2929 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2931 myText->setElideMode(QQuickText::ElideNone);
2932 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2934 myText->setFontSizeMode(QQuickText::VerticalFit);
2935 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2936 // VerticalFit should reduce the size to the wrapped text within the vertical height.
2937 verticalFitHeight = myText->contentHeight();
2938 qreal verticalFitWidth = myText->contentWidth();
2939 QVERIFY(myText->contentWidth() <= myText->width() + 2);
2940 QVERIFY(verticalFitHeight <= myText->height() + 2);
2941 QVERIFY(verticalFitHeight < originalHeight);
2943 // Elide won't affect the height or width of a wrapped text with VerticalFit.
2944 myText->setElideMode(QQuickText::ElideRight);
2945 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2946 QVERIFY(!myText->truncated());
2947 QCOMPARE(myText->contentWidth(), verticalFitWidth);
2948 QCOMPARE(myText->contentHeight(), verticalFitHeight);
2950 myText->setElideMode(QQuickText::ElideNone);
2951 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2953 myText->setFontSizeMode(QQuickText::Fit);
2954 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2955 // Should be the same as VerticalFit with wrapping.
2956 QCOMPARE(myText->contentWidth(), verticalFitWidth);
2957 QCOMPARE(myText->contentHeight(), verticalFitHeight);
2959 // Elide won't affect the size with Fit.
2960 myText->setElideMode(QQuickText::ElideRight);
2961 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2962 QVERIFY(!myText->truncated());
2963 QCOMPARE(myText->contentWidth(), verticalFitWidth);
2964 QCOMPARE(myText->contentHeight(), verticalFitHeight);
2966 myText->setElideMode(QQuickText::ElideNone);
2967 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2969 myText->setFontSizeMode(QQuickText::FixedSize);
2970 myText->setMaximumLineCount(2);
2971 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2973 // The original text wrapped should exceed the height of the item.
2974 QVERIFY(originalWidth <= myText->width() + 2);
2975 QVERIFY(originalHeight > myText->height());
2977 myText->setFontSizeMode(QQuickText::HorizontalFit);
2978 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2979 // HorizontalFit should reduce the font size to minimize wrapping, which brings it back to the
2980 // same size as without text wrapping.
2981 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2982 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2984 // Elide won't affect the size with HorizontalFit.
2985 myText->setElideMode(QQuickText::ElideRight);
2986 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2987 QVERIFY(!myText->truncated());
2988 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2989 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2991 myText->setElideMode(QQuickText::ElideNone);
2992 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2994 myText->setFontSizeMode(QQuickText::VerticalFit);
2995 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2996 // VerticalFit should reduce the size to the wrapped text within the vertical height.
2997 verticalFitHeight = myText->contentHeight();
2998 verticalFitWidth = myText->contentWidth();
2999 QVERIFY(myText->contentWidth() <= myText->width() + 2);
3000 QVERIFY(verticalFitHeight <= myText->height() + 2);
3001 QVERIFY(verticalFitHeight < originalHeight);
3003 // Elide won't affect the height or width of a wrapped text with VerticalFit.
3004 myText->setElideMode(QQuickText::ElideRight);
3005 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3006 QVERIFY(!myText->truncated());
3007 QCOMPARE(myText->contentWidth(), verticalFitWidth);
3008 QCOMPARE(myText->contentHeight(), verticalFitHeight);
3010 myText->setElideMode(QQuickText::ElideNone);
3011 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3013 myText->setFontSizeMode(QQuickText::Fit);
3014 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3015 // Should be the same as VerticalFit with wrapping.
3016 QCOMPARE(myText->contentWidth(), verticalFitWidth);
3017 QCOMPARE(myText->contentHeight(), verticalFitHeight);
3019 // Elide won't affect the size with Fit.
3020 myText->setElideMode(QQuickText::ElideRight);
3021 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3022 QVERIFY(!myText->truncated());
3023 QCOMPARE(myText->contentWidth(), verticalFitWidth);
3024 QCOMPARE(myText->contentHeight(), verticalFitHeight);
3026 myText->setElideMode(QQuickText::ElideNone);
3027 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3030 void tst_qquicktext::fontSizeModeMultiline_data()
3032 QTest::addColumn<QString>("text");
3033 QTest::newRow("plain") << "The quick red fox jumped\n over the lazy brown dog";
3034 QTest::newRow("styledtext") << "<b>The quick red fox jumped<br/> over the lazy brown dog</b>";
3037 void tst_qquicktext::fontSizeModeMultiline()
3039 QFETCH(QString, text);
3041 QScopedPointer<QQuickView> window(createView(testFile("fontSizeMode.qml")));
3044 QQuickText *myText = window->rootObject()->findChild<QQuickText*>("myText");
3045 QVERIFY(myText != 0);
3047 myText->setText(text);
3048 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3050 qreal originalWidth = myText->contentWidth();
3051 qreal originalHeight = myText->contentHeight();
3052 QCOMPARE(myText->lineCount(), 2);
3054 // The original text unwrapped should exceed the width and height of the item.
3055 QVERIFY(originalWidth > myText->width());
3056 QVERIFY(originalHeight > myText->height());
3058 QFont font = myText->font();
3059 font.setPixelSize(64);
3061 myText->setFont(font);
3062 myText->setFontSizeMode(QQuickText::HorizontalFit);
3063 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3064 // Font size reduced to fit within the width of the item.
3065 QCOMPARE(myText->lineCount(), 2);
3066 qreal horizontalFitWidth = myText->contentWidth();
3067 qreal horizontalFitHeight = myText->contentHeight();
3068 QVERIFY(horizontalFitWidth <= myText->width() + 2); // rounding
3069 QVERIFY(horizontalFitHeight > myText->height());
3071 // Right eliding will remove the last line
3072 myText->setElideMode(QQuickText::ElideRight);
3073 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3074 QVERIFY(myText->truncated());
3075 QCOMPARE(myText->lineCount(), 1);
3076 QVERIFY(myText->contentWidth() <= myText->width() + 2);
3077 QVERIFY(myText->contentHeight() <= myText->height() + 2);
3079 // Left or middle eliding wont have any effect.
3080 myText->setElideMode(QQuickText::ElideLeft);
3081 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3082 QVERIFY(!myText->truncated());
3083 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
3084 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
3086 myText->setElideMode(QQuickText::ElideMiddle);
3087 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3088 QVERIFY(!myText->truncated());
3089 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
3090 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
3092 myText->setElideMode(QQuickText::ElideNone);
3093 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3095 myText->setFontSizeMode(QQuickText::VerticalFit);
3096 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3097 // Font size reduced to fit within the height of the item.
3098 qreal verticalFitWidth = myText->contentWidth();
3099 qreal verticalFitHeight = myText->contentHeight();
3100 QVERIFY(verticalFitWidth <= myText->width() + 2);
3101 QVERIFY(verticalFitHeight <= myText->height() + 2);
3103 // Elide will have no effect.
3104 myText->setElideMode(QQuickText::ElideRight);
3105 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3106 QVERIFY(!myText->truncated());
3107 QVERIFY(myText->contentWidth() <= myText->width() + 2);
3108 QCOMPARE(myText->contentWidth(), verticalFitWidth);
3109 QCOMPARE(myText->contentHeight(), verticalFitHeight);
3111 myText->setElideMode(QQuickText::ElideLeft);
3112 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3113 QVERIFY(!myText->truncated());
3114 QCOMPARE(myText->contentWidth(), verticalFitWidth);
3115 QCOMPARE(myText->contentHeight(), verticalFitHeight);
3117 myText->setElideMode(QQuickText::ElideMiddle);
3118 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3119 QVERIFY(!myText->truncated());
3120 QCOMPARE(myText->contentWidth(), verticalFitWidth);
3121 QCOMPARE(myText->contentHeight(), verticalFitHeight);
3123 myText->setElideMode(QQuickText::ElideNone);
3124 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3126 myText->setFontSizeMode(QQuickText::Fit);
3127 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3128 // Should be the same as VerticalFit with no wrapping.
3129 QCOMPARE(myText->contentWidth(), verticalFitWidth);
3130 QCOMPARE(myText->contentHeight(), verticalFitHeight);
3132 // Elide won't affect the size with Fit.
3133 myText->setElideMode(QQuickText::ElideRight);
3134 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3135 QVERIFY(!myText->truncated());
3136 QCOMPARE(myText->contentWidth(), verticalFitWidth);
3137 QCOMPARE(myText->contentHeight(), verticalFitHeight);
3139 myText->setElideMode(QQuickText::ElideLeft);
3140 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3141 QVERIFY(!myText->truncated());
3142 QCOMPARE(myText->contentWidth(), verticalFitWidth);
3143 QCOMPARE(myText->contentHeight(), verticalFitHeight);
3145 myText->setElideMode(QQuickText::ElideMiddle);
3146 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3147 QVERIFY(!myText->truncated());
3148 QCOMPARE(myText->contentWidth(), verticalFitWidth);
3149 QCOMPARE(myText->contentHeight(), verticalFitHeight);
3151 myText->setElideMode(QQuickText::ElideNone);
3152 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3154 myText->setFontSizeMode(QQuickText::FixedSize);
3155 myText->setWrapMode(QQuickText::Wrap);
3156 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3158 originalWidth = myText->contentWidth();
3159 originalHeight = myText->contentHeight();
3161 // The original text wrapped should exceed the height of the item.
3162 QVERIFY(originalWidth <= myText->width() + 2);
3163 QVERIFY(originalHeight > myText->height());
3165 myText->setFontSizeMode(QQuickText::HorizontalFit);
3166 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3167 // HorizontalFit should reduce the font size to minimize wrapping, which brings it back to the
3168 // same size as without text wrapping.
3169 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
3170 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
3172 // Text will be elided vertically with HorizontalFit
3173 myText->setElideMode(QQuickText::ElideRight);
3174 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3175 QVERIFY(myText->truncated());
3176 QVERIFY(myText->contentWidth() <= myText->width() + 2);
3177 QVERIFY(myText->contentHeight() <= myText->height() + 2);
3179 myText->setElideMode(QQuickText::ElideNone);
3180 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3182 myText->setFontSizeMode(QQuickText::VerticalFit);
3183 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3184 // VerticalFit should reduce the size to the wrapped text within the vertical height.
3185 verticalFitHeight = myText->contentHeight();
3186 verticalFitWidth = myText->contentWidth();
3187 QVERIFY(myText->contentWidth() <= myText->width() + 2);
3188 QVERIFY(verticalFitHeight <= myText->height() + 2);
3189 QVERIFY(verticalFitHeight < originalHeight);
3191 // Elide won't affect the height or width of a wrapped text with VerticalFit.
3192 myText->setElideMode(QQuickText::ElideRight);
3193 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3194 QVERIFY(!myText->truncated());
3195 QCOMPARE(myText->contentWidth(), verticalFitWidth);
3196 QCOMPARE(myText->contentHeight(), verticalFitHeight);
3198 myText->setElideMode(QQuickText::ElideNone);
3199 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3201 myText->setFontSizeMode(QQuickText::Fit);
3202 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3203 // Should be the same as VerticalFit with wrapping.
3204 QCOMPARE(myText->contentWidth(), verticalFitWidth);
3205 QCOMPARE(myText->contentHeight(), verticalFitHeight);
3207 // Elide won't affect the size with Fit.
3208 myText->setElideMode(QQuickText::ElideRight);
3209 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3210 QVERIFY(!myText->truncated());
3211 QCOMPARE(myText->contentWidth(), verticalFitWidth);
3212 QCOMPARE(myText->contentHeight(), verticalFitHeight);
3214 myText->setElideMode(QQuickText::ElideNone);
3215 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3217 myText->setFontSizeMode(QQuickText::FixedSize);
3218 myText->setMaximumLineCount(2);
3219 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3221 // The original text wrapped should exceed the height of the item.
3222 QVERIFY(originalWidth <= myText->width() + 2);
3223 QVERIFY(originalHeight > myText->height());
3225 myText->setFontSizeMode(QQuickText::HorizontalFit);
3226 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3227 // HorizontalFit should reduce the font size to minimize wrapping, which brings it back to the
3228 // same size as without text wrapping.
3229 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
3230 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
3232 // Elide won't affect the size with HorizontalFit.
3233 myText->setElideMode(QQuickText::ElideRight);
3234 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3235 QVERIFY(myText->truncated());
3236 QVERIFY(myText->contentWidth() <= myText->width() + 2);
3237 QVERIFY(myText->contentHeight() <= myText->height() + 2);
3239 myText->setElideMode(QQuickText::ElideNone);
3240 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3242 myText->setFontSizeMode(QQuickText::VerticalFit);
3243 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3244 // VerticalFit should reduce the size to the wrapped text within the vertical height.
3245 verticalFitHeight = myText->contentHeight();
3246 verticalFitWidth = myText->contentWidth();
3247 QVERIFY(myText->contentWidth() <= myText->width() + 2);
3248 QVERIFY(verticalFitHeight <= myText->height() + 2);
3249 QVERIFY(verticalFitHeight < originalHeight);
3251 // Elide won't affect the height or width of a wrapped text with VerticalFit.
3252 myText->setElideMode(QQuickText::ElideRight);
3253 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3254 QVERIFY(!myText->truncated());
3255 QCOMPARE(myText->contentWidth(), verticalFitWidth);
3256 QCOMPARE(myText->contentHeight(), verticalFitHeight);
3258 myText->setElideMode(QQuickText::ElideNone);
3259 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3261 myText->setFontSizeMode(QQuickText::Fit);
3262 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3263 // Should be the same as VerticalFit with wrapping.
3264 QCOMPARE(myText->contentWidth(), verticalFitWidth);
3265 QCOMPARE(myText->contentHeight(), verticalFitHeight);
3267 // Elide won't affect the size with Fit.
3268 myText->setElideMode(QQuickText::ElideRight);
3269 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3270 QVERIFY(!myText->truncated());
3271 QCOMPARE(myText->contentWidth(), verticalFitWidth);
3272 QCOMPARE(myText->contentHeight(), verticalFitHeight);
3274 myText->setElideMode(QQuickText::ElideNone);
3275 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3278 void tst_qquicktext::multilengthStrings_data()
3280 QTest::addColumn<QString>("source");
3281 QTest::newRow("No Wrap") << testFile("multilengthStrings.qml");
3282 QTest::newRow("Wrap") << testFile("multilengthStringsWrapped.qml");
3285 void tst_qquicktext::multilengthStrings()
3287 QFETCH(QString, source);
3289 QScopedPointer<QQuickView> window(createView(source));
3292 QQuickText *myText = window->rootObject()->findChild<QQuickText*>("myText");
3293 QVERIFY(myText != 0);
3295 const QString longText = "the quick brown fox jumped over the lazy dog";
3296 const QString mediumText = "the brown fox jumped over the dog";
3297 const QString shortText = "fox jumped dog";
3299 myText->setText(longText);
3300 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3301 const qreal longWidth = myText->contentWidth();
3302 const qreal longHeight = myText->contentHeight();
3304 myText->setText(mediumText);
3305 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3306 const qreal mediumWidth = myText->contentWidth();
3307 const qreal mediumHeight = myText->contentHeight();
3309 myText->setText(shortText);
3310 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3311 const qreal shortWidth = myText->contentWidth();
3312 const qreal shortHeight = myText->contentHeight();
3314 myText->setElideMode(QQuickText::ElideRight);
3315 myText->setText(longText + QLatin1Char('\x9c') + mediumText + QLatin1Char('\x9c') + shortText);
3317 myText->setSize(QSizeF(longWidth, longHeight));
3318 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3320 QCOMPARE(myText->contentWidth(), longWidth);
3321 QCOMPARE(myText->contentHeight(), longHeight);
3322 QCOMPARE(myText->truncated(), false);
3324 myText->setSize(QSizeF(mediumWidth, mediumHeight));
3325 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3327 QCOMPARE(myText->contentWidth(), mediumWidth);
3328 QCOMPARE(myText->contentHeight(), mediumHeight);
3329 QCOMPARE(myText->truncated(), true);
3331 myText->setSize(QSizeF(shortWidth, shortHeight));
3332 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3334 QCOMPARE(myText->contentWidth(), shortWidth);
3335 QCOMPARE(myText->contentHeight(), shortHeight);
3336 QCOMPARE(myText->truncated(), true);
3339 void tst_qquicktext::fontFormatSizes_data()
3341 QTest::addColumn<QString>("text");
3342 QTest::addColumn<QString>("textWithTag");
3343 QTest::addColumn<bool>("fontIsBigger");
3345 QTest::newRow("fs1") << "Hello world!" << "Hello <font size=\"1\">world</font>!" << false;
3346 QTest::newRow("fs2") << "Hello world!" << "Hello <font size=\"2\">world</font>!" << false;
3347 QTest::newRow("fs3") << "Hello world!" << "Hello <font size=\"3\">world</font>!" << false;
3348 QTest::newRow("fs4") << "Hello world!" << "Hello <font size=\"4\">world</font>!" << true;
3349 QTest::newRow("fs5") << "Hello world!" << "Hello <font size=\"5\">world</font>!" << true;
3350 QTest::newRow("fs6") << "Hello world!" << "Hello <font size=\"6\">world</font>!" << true;
3351 QTest::newRow("fs7") << "Hello world!" << "Hello <font size=\"7\">world</font>!" << true;
3352 QTest::newRow("h1") << "This is<br/>a font<br/> size test." << "This is <h1>a font</h1> size test." << true;
3353 QTest::newRow("h2") << "This is<br/>a font<br/> size test." << "This is <h2>a font</h2> size test." << true;
3354 QTest::newRow("h3") << "This is<br/>a font<br/> size test." << "This is <h3>a font</h3> size test." << true;
3355 QTest::newRow("h4") << "This is<br/>a font<br/> size test." << "This is <h4>a font</h4> size test." << true;
3356 QTest::newRow("h5") << "This is<br/>a font<br/> size test." << "This is <h5>a font</h5> size test." << false;
3357 QTest::newRow("h6") << "This is<br/>a font<br/> size test." << "This is <h6>a font</h6> size test." << false;
3360 void tst_qquicktext::fontFormatSizes()
3362 QFETCH(QString, text);
3363 QFETCH(QString, textWithTag);
3364 QFETCH(bool, fontIsBigger);
3366 QQuickView *view = new QQuickView;
3368 view->setSource(testFileUrl("pointFontSizes.qml"));
3371 QQuickText *qtext = view->rootObject()->findChild<QQuickText*>("text");
3372 QQuickText *qtextWithTag = view->rootObject()->findChild<QQuickText*>("textWithTag");
3373 QVERIFY(qtext != 0);
3374 QVERIFY(qtextWithTag != 0);
3376 qtext->setText(text);
3377 qtextWithTag->setText(textWithTag);
3379 for (int size = 6; size < 100; size += 4) {
3380 view->rootObject()->setProperty("pointSize", size);
3382 QVERIFY(qtext->height() <= qtextWithTag->height());
3384 QVERIFY(qtext->height() >= qtextWithTag->height());
3389 view->setSource(testFileUrl("pixelFontSizes.qml"));
3390 QQuickText *qtext = view->rootObject()->findChild<QQuickText*>("text");
3391 QQuickText *qtextWithTag = view->rootObject()->findChild<QQuickText*>("textWithTag");
3392 QVERIFY(qtext != 0);
3393 QVERIFY(qtextWithTag != 0);
3395 qtext->setText(text);
3396 qtextWithTag->setText(textWithTag);
3398 for (int size = 6; size < 100; size += 4) {
3399 view->rootObject()->setProperty("pixelSize", size);
3401 QVERIFY(qtext->height() <= qtextWithTag->height());
3403 QVERIFY(qtext->height() >= qtextWithTag->height());
3409 typedef qreal (*ExpectedBaseline)(QQuickText *item);
3410 Q_DECLARE_METATYPE(ExpectedBaseline)
3412 static qreal expectedBaselineTop(QQuickText *item)
3414 QFontMetricsF fm(item->font());
3418 static qreal expectedBaselineBottom(QQuickText *item)
3420 QFontMetricsF fm(item->font());
3421 return item->height() - item->contentHeight() + fm.ascent();
3424 static qreal expectedBaselineCenter(QQuickText *item)
3426 QFontMetricsF fm(item->font());
3427 return ((item->height() - item->contentHeight()) / 2) + fm.ascent();
3430 static qreal expectedBaselineBold(QQuickText *item)
3432 QFont font = item->font();
3434 QFontMetricsF fm(font);
3438 static qreal expectedBaselineImage(QQuickText *item)
3440 QFontMetricsF fm(item->font());
3441 // The line is positioned so the bottom of the line is aligned with the bottom of the image,
3442 // or image height - line height and the baseline is line position + ascent. Because
3443 // QTextLine's height is rounded up this can give slightly different results to image height
3445 return 181 - qCeil(fm.height()) + fm.ascent();
3448 static qreal expectedBaselineCustom(QQuickText *item)
3450 QFontMetricsF fm(item->font());
3451 return 16 + fm.ascent();
3454 static qreal expectedBaselineScaled(QQuickText *item)
3456 QFont font = item->font();
3457 QTextLayout layout(item->text().replace(QLatin1Char('\n'), QChar::LineSeparator));
3459 layout.setFont(font);
3461 layout.beginLayout();
3462 for (QTextLine line = layout.createLine(); line.isValid(); line = layout.createLine()) {
3463 line.setLineWidth(FLT_MAX);
3464 width = qMax(line.naturalTextWidth(), width);
3468 if (width < item->width()) {
3469 QFontMetricsF fm(layout.font());
3472 font.setPointSize(font.pointSize() - 1);
3473 } while (font.pointSize() > 0);
3477 static qreal expectedBaselineFixedBottom(QQuickText *item)
3479 QFontMetricsF fm(item->font());
3480 qreal dy = item->text().contains(QLatin1Char('\n'))
3483 return dy + fm.ascent();
3486 static qreal expectedBaselineProportionalBottom(QQuickText *item)
3488 QFontMetricsF fm(item->font());
3489 qreal dy = item->text().contains(QLatin1Char('\n'))
3490 ? 200 - (qCeil(fm.height()) * 3)
3491 : 200 - (qCeil(fm.height()) * 1.5);
3492 return dy + fm.ascent();
3495 void tst_qquicktext::baselineOffset_data()
3497 qRegisterMetaType<ExpectedBaseline>();
3498 QTest::addColumn<QString>("text");
3499 QTest::addColumn<QString>("wrappedText");
3500 QTest::addColumn<QByteArray>("bindings");
3501 QTest::addColumn<ExpectedBaseline>("expectedBaseline");
3502 QTest::addColumn<ExpectedBaseline>("expectedBaselineEmpty");
3504 QTest::newRow("top align")
3507 << QByteArray("height: 200; verticalAlignment: Text.AlignTop")
3508 << &expectedBaselineTop
3509 << &expectedBaselineTop;
3510 QTest::newRow("bottom align")
3513 << QByteArray("height: 200; verticalAlignment: Text.AlignBottom")
3514 << &expectedBaselineBottom
3515 << &expectedBaselineBottom;
3516 QTest::newRow("center align")
3519 << QByteArray("height: 200; verticalAlignment: Text.AlignVCenter")
3520 << &expectedBaselineCenter
3521 << &expectedBaselineCenter;
3523 QTest::newRow("bold")
3524 << "<b>hello world</b>"
3525 << "<b>hello<br/>world</b>"
3526 << QByteArray("height: 200")
3527 << &expectedBaselineTop
3528 << &expectedBaselineBold;
3530 QTest::newRow("richText")
3531 << "<b>hello world</b>"
3532 << "<b>hello<br/>world</b>"
3533 << QByteArray("height: 200; textFormat: Text.RichText")
3534 << &expectedBaselineTop
3535 << &expectedBaselineTop;
3537 QTest::newRow("elided")
3540 << QByteArray("width: 20; height: 8; elide: Text.ElideRight")
3541 << &expectedBaselineTop
3542 << &expectedBaselineTop;
3544 QTest::newRow("elided bottom align")
3546 << "hello\nworld!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
3547 << QByteArray("width: 200; height: 200; elide: Text.ElideRight; verticalAlignment: Text.AlignBottom")
3548 << &expectedBaselineBottom
3549 << &expectedBaselineBottom;
3551 QTest::newRow("image")
3552 << "hello <img src=\"images/heart200.png\" /> world"
3553 << "hello <img src=\"images/heart200.png\" /><br/>world"
3554 << QByteArray("height: 200\n; baseUrl: \"") + testFileUrl("reference").toEncoded() + QByteArray("\"")
3555 << &expectedBaselineImage
3556 << &expectedBaselineTop;
3558 QTest::newRow("customLine")
3561 << QByteArray("height: 200; onLineLaidOut: line.y += 16")
3562 << &expectedBaselineCustom
3563 << &expectedBaselineCustom;
3565 QTest::newRow("scaled font")
3568 << QByteArray("width: 200; minimumPointSize: 1; font.pointSize: 64; fontSizeMode: Text.HorizontalFit")
3569 << &expectedBaselineScaled
3570 << &expectedBaselineTop;
3572 QTest::newRow("fixed line height top align")
3575 << QByteArray("height: 200; lineHeightMode: Text.FixedHeight; lineHeight: 20; verticalAlignment: Text.AlignTop")
3576 << &expectedBaselineTop
3577 << &expectedBaselineTop;
3579 QTest::newRow("fixed line height bottom align")
3582 << QByteArray("height: 200; lineHeightMode: Text.FixedHeight; lineHeight: 20; verticalAlignment: Text.AlignBottom")
3583 << &expectedBaselineFixedBottom
3584 << &expectedBaselineFixedBottom;
3586 QTest::newRow("proportional line height top align")
3589 << QByteArray("height: 200; lineHeightMode: Text.ProportionalHeight; lineHeight: 1.5; verticalAlignment: Text.AlignTop")
3590 << &expectedBaselineTop
3591 << &expectedBaselineTop;
3593 QTest::newRow("proportional line height bottom align")
3596 << QByteArray("height: 200; lineHeightMode: Text.ProportionalHeight; lineHeight: 1.5; verticalAlignment: Text.AlignBottom")
3597 << &expectedBaselineProportionalBottom
3598 << &expectedBaselineProportionalBottom;
3601 void tst_qquicktext::baselineOffset()
3603 QFETCH(QString, text);
3604 QFETCH(QString, wrappedText);
3605 QFETCH(QByteArray, bindings);
3606 QFETCH(ExpectedBaseline, expectedBaseline);
3607 QFETCH(ExpectedBaseline, expectedBaselineEmpty);
3609 QQmlComponent component(&engine);
3611 "import QtQuick 2.0\n"
3616 QScopedPointer<QObject> object(component.create());
3618 QQuickText *item = qobject_cast<QQuickText *>(object.data());
3622 qreal baseline = expectedBaselineEmpty(item);
3624 QCOMPARE(item->baselineOffset(), baseline);
3626 item->setText(text);
3627 if (expectedBaseline != expectedBaselineEmpty)
3628 baseline = expectedBaseline(item);
3630 QCOMPARE(item->baselineOffset(), baseline);
3632 item->setText(wrappedText);
3633 QCOMPARE(item->baselineOffset(), expectedBaseline(item));
3636 QFont font = item->font();
3637 font.setPointSize(font.pointSize() + 8);
3640 QCOMPARE(item->baselineOffset(), expectedBaseline(item));
3642 item->setText(text);
3643 qreal baseline = expectedBaseline(item);
3644 QCOMPARE(item->baselineOffset(), baseline);
3646 item->setText(QString());
3647 if (expectedBaselineEmpty != expectedBaseline)
3648 baseline = expectedBaselineEmpty(item);
3650 QCOMPARE(item->baselineOffset(), baseline);
3654 void tst_qquicktext::htmlLists()
3656 QFETCH(QString, text);
3657 QFETCH(int, nbLines);
3659 QQuickView *view = createView(testFile("htmlLists.qml"));
3660 QQuickText *textObject = view->rootObject()->findChild<QQuickText*>("myText");
3662 QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject);
3663 QVERIFY(textPrivate != 0);
3664 QVERIFY(textPrivate->extra.isAllocated());
3666 QVERIFY(textObject != 0);
3667 textObject->setText(text);
3670 view->requestActivateWindow();
3671 QVERIFY(QTest::qWaitForWindowActive(view));
3673 QCOMPARE(textPrivate->extra->doc->lineCount(), nbLines);
3678 void tst_qquicktext::htmlLists_data()
3680 QTest::addColumn<QString>("text");
3681 QTest::addColumn<int>("nbLines");
3683 QTest::newRow("ordered list") << "<ol><li>one<li>two<li>three" << 3;
3684 QTest::newRow("ordered list closed") << "<ol><li>one</li></ol>" << 1;
3685 QTest::newRow("ordered list alpha") << "<ol type=\"a\"><li>one</li><li>two</li></ol>" << 2;
3686 QTest::newRow("ordered list upper alpha") << "<ol type=\"A\"><li>one</li><li>two</li></ol>" << 2;
3687 QTest::newRow("ordered list roman") << "<ol type=\"i\"><li>one</li><li>two</li></ol>" << 2;
3688 QTest::newRow("ordered list upper roman") << "<ol type=\"I\"><li>one</li><li>two</li></ol>" << 2;
3689 QTest::newRow("ordered list bad") << "<ol type=\"z\"><li>one</li><li>two</li></ol>" << 2;
3690 QTest::newRow("unordered list") << "<ul><li>one<li>two" << 2;
3691 QTest::newRow("unordered list closed") << "<ul><li>one</li><li>two</li></ul>" << 2;
3692 QTest::newRow("unordered list disc") << "<ul type=\"disc\"><li>one</li><li>two</li></ul>" << 2;
3693 QTest::newRow("unordered list square") << "<ul type=\"square\"><li>one</li><li>two</li></ul>" << 2;
3694 QTest::newRow("unordered list bad") << "<ul type=\"bad\"><li>one</li><li>two</li></ul>" << 2;
3697 QTEST_MAIN(tst_qquicktext)
3699 #include "tst_qquicktext.moc"