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 Q_DECLARE_METATYPE(QQuickText::TextFormat)
62 class tst_qquicktext : public QQmlDataTest
73 void multilineElide_data();
74 void multilineElide();
75 void implicitElide_data();
79 void alignments_data();
83 void embeddedImages_data();
84 void embeddedImages();
89 // ### these tests may be trivial
90 void horizontalAlignment();
91 void horizontalAlignment_RightToLeft();
92 void verticalAlignment();
98 // QQuickFontValueType
103 void capitalization();
104 void letterSpacing();
109 void implicitSize_data();
112 void implicitSizeBinding_data();
113 void implicitSizeBinding();
115 void boundingRect_data();
120 void imgTagsBaseUrl_data();
121 void imgTagsBaseUrl();
122 void imgTagsAlign_data();
124 void imgTagsMultipleImages();
126 void imgTagsUpdates();
128 void fontSizeMode_data();
130 void fontSizeModeMultiline_data();
131 void fontSizeModeMultiline();
132 void multilengthStrings_data();
133 void multilengthStrings();
134 void fontFormatSizes_data();
135 void fontFormatSizes();
137 void baselineOffset_data();
138 void baselineOffset();
141 QStringList standard;
142 QStringList richText;
144 QStringList horizontalAlignmentmentStrings;
145 QStringList verticalAlignmentmentStrings;
147 QList<Qt::Alignment> verticalAlignmentments;
148 QList<Qt::Alignment> horizontalAlignmentments;
150 QStringList styleStrings;
151 QList<QQuickText::TextStyle> styles;
153 QStringList colorStrings;
157 QQuickView *createView(const QString &filename);
160 tst_qquicktext::tst_qquicktext()
162 standard << "the quick brown fox jumped over the lazy dog"
163 << "the quick brown fox\n jumped over the lazy dog";
165 richText << "<i>the <b>quick</b> brown <a href=\\\"http://www.google.com\\\">fox</a> jumped over the <b>lazy</b> dog</i>"
166 << "<i>the <b>quick</b> brown <a href=\\\"http://www.google.com\\\">fox</a><br>jumped over the <b>lazy</b> dog</i>";
168 horizontalAlignmentmentStrings << "AlignLeft"
172 verticalAlignmentmentStrings << "AlignTop"
176 horizontalAlignmentments << Qt::AlignLeft
180 verticalAlignmentments << Qt::AlignTop
184 styleStrings << "Normal"
189 styles << QQuickText::Normal
190 << QQuickText::Outline
191 << QQuickText::Raised
192 << QQuickText::Sunken;
194 colorStrings << "aliceblue"
207 // need a different test to do alpha channel test
213 QQuickView *tst_qquicktext::createView(const QString &filename)
215 QQuickView *canvas = new QQuickView(0);
217 canvas->setSource(QUrl::fromLocalFile(filename));
221 void tst_qquicktext::text()
224 QQmlComponent textComponent(&engine);
225 textComponent.setData("import QtQuick 2.0\nText { text: \"\" }", QUrl::fromLocalFile(""));
226 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
228 QVERIFY(textObject != 0);
229 QCOMPARE(textObject->text(), QString(""));
230 QVERIFY(textObject->width() == 0);
235 for (int i = 0; i < standard.size(); i++)
237 QString componentStr = "import QtQuick 2.0\nText { text: \"" + standard.at(i) + "\" }";
238 QQmlComponent textComponent(&engine);
239 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
241 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
243 QVERIFY(textObject != 0);
244 QCOMPARE(textObject->text(), standard.at(i));
245 QVERIFY(textObject->width() > 0);
250 for (int i = 0; i < richText.size(); i++)
252 QString componentStr = "import QtQuick 2.0\nText { text: \"" + richText.at(i) + "\" }";
253 QQmlComponent textComponent(&engine);
254 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
255 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
257 QVERIFY(textObject != 0);
258 QString expected = richText.at(i);
259 QCOMPARE(textObject->text(), expected.replace("\\\"", "\""));
260 QVERIFY(textObject->width() > 0);
266 void tst_qquicktext::width()
268 // uses Font metrics to find the width for standard and document to find the width for rich
270 QQmlComponent textComponent(&engine);
271 textComponent.setData("import QtQuick 2.0\nText { text: \"\" }", QUrl::fromLocalFile(""));
272 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
274 QVERIFY(textObject != 0);
275 QCOMPARE(textObject->width(), 0.);
280 bool requiresUnhintedMetrics = !qmlDisableDistanceField();
282 for (int i = 0; i < standard.size(); i++)
284 QVERIFY(!Qt::mightBeRichText(standard.at(i))); // self-test
287 qreal metricWidth = 0.0;
289 if (requiresUnhintedMetrics) {
290 QString s = standard.at(i);
291 s.replace(QLatin1Char('\n'), QChar::LineSeparator);
293 QTextLayout layout(s);
294 layout.setFlags(Qt::TextExpandTabs | Qt::TextShowMnemonic);
297 option.setUseDesignMetrics(true);
298 layout.setTextOption(option);
301 layout.beginLayout();
303 QTextLine line = layout.createLine();
310 metricWidth = layout.boundingRect().width();
313 metricWidth = fm.size(Qt::TextExpandTabs && Qt::TextShowMnemonic, standard.at(i)).width();
316 QString componentStr = "import QtQuick 2.0\nText { text: \"" + standard.at(i) + "\" }";
317 QQmlComponent textComponent(&engine);
318 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
319 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
321 QVERIFY(textObject != 0);
322 QVERIFY(textObject->boundingRect().width() > 0);
323 QCOMPARE(textObject->width(), qreal(metricWidth));
324 QVERIFY(textObject->textFormat() == QQuickText::AutoText); // setting text doesn't change format
329 for (int i = 0; i < richText.size(); i++)
331 QVERIFY(Qt::mightBeRichText(richText.at(i))); // self-test
333 QString componentStr = "import QtQuick 2.0\nText { text: \"" + richText.at(i) + "\"; textFormat: Text.RichText }";
334 QQmlComponent textComponent(&engine);
335 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
336 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
337 QVERIFY(textObject != 0);
339 QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject);
340 QVERIFY(textPrivate != 0);
341 QVERIFY(textPrivate->extra.isAllocated());
343 QTextDocument *doc = textPrivate->extra->doc;
346 QCOMPARE(int(textObject->width()), int(doc->idealWidth()));
347 QVERIFY(textObject->textFormat() == QQuickText::RichText);
353 void tst_qquicktext::wrap()
356 // for specified width and wrap set true
358 QQmlComponent textComponent(&engine);
359 textComponent.setData("import QtQuick 2.0\nText { text: \"Hello\"; wrapMode: Text.WordWrap; width: 300 }", QUrl::fromLocalFile(""));
360 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
361 textHeight = textObject->height();
363 QVERIFY(textObject != 0);
364 QVERIFY(textObject->wrapMode() == QQuickText::WordWrap);
365 QCOMPARE(textObject->width(), 300.);
370 for (int i = 0; i < standard.size(); i++)
372 QString componentStr = "import QtQuick 2.0\nText { wrapMode: Text.WordWrap; width: 30; text: \"" + standard.at(i) + "\" }";
373 QQmlComponent textComponent(&engine);
374 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
375 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
377 QVERIFY(textObject != 0);
378 QCOMPARE(textObject->width(), 30.);
379 QVERIFY(textObject->height() > textHeight);
381 int oldHeight = textObject->height();
382 textObject->setWidth(100);
383 QVERIFY(textObject->height() < oldHeight);
388 for (int i = 0; i < richText.size(); i++)
390 QString componentStr = "import QtQuick 2.0\nText { wrapMode: Text.WordWrap; width: 30; text: \"" + richText.at(i) + "\" }";
391 QQmlComponent textComponent(&engine);
392 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
393 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
395 QVERIFY(textObject != 0);
396 QCOMPARE(textObject->width(), 30.);
397 QVERIFY(textObject->height() > textHeight);
399 qreal oldHeight = textObject->height();
400 textObject->setWidth(100);
401 QVERIFY(textObject->height() < oldHeight);
406 // richtext again with a fixed height
407 for (int i = 0; i < richText.size(); i++)
409 QString componentStr = "import QtQuick 2.0\nText { wrapMode: Text.WordWrap; width: 30; height: 50; text: \"" + richText.at(i) + "\" }";
410 QQmlComponent textComponent(&engine);
411 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
412 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
414 QVERIFY(textObject != 0);
415 QCOMPARE(textObject->width(), 30.);
416 QVERIFY(textObject->implicitHeight() > textHeight);
418 qreal oldHeight = textObject->implicitHeight();
419 textObject->setWidth(100);
420 QVERIFY(textObject->implicitHeight() < oldHeight);
426 void tst_qquicktext::elide()
428 for (QQuickText::TextElideMode m = QQuickText::ElideLeft; m<=QQuickText::ElideNone; m=QQuickText::TextElideMode(int(m)+1)) {
429 const char* elidename[]={"ElideLeft", "ElideRight", "ElideMiddle", "ElideNone"};
430 QString elide = "elide: Text." + QString(elidename[int(m)]) + ";";
432 // XXX Poor coverage.
435 QQmlComponent textComponent(&engine);
436 textComponent.setData(("import QtQuick 2.0\nText { text: \"\"; "+elide+" width: 100 }").toLatin1(), QUrl::fromLocalFile(""));
437 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
439 QCOMPARE(textObject->elideMode(), m);
440 QCOMPARE(textObject->width(), 100.);
445 for (int i = 0; i < standard.size(); i++)
447 QString componentStr = "import QtQuick 2.0\nText { "+elide+" width: 100; text: \"" + standard.at(i) + "\" }";
448 QQmlComponent textComponent(&engine);
449 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
450 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
452 QCOMPARE(textObject->elideMode(), m);
453 QCOMPARE(textObject->width(), 100.);
455 if (m != QQuickText::ElideNone && !standard.at(i).contains('\n'))
456 QVERIFY(textObject->contentWidth() <= textObject->width());
461 for (int i = 0; i < richText.size(); i++)
463 QString componentStr = "import QtQuick 2.0\nText { "+elide+" width: 100; text: \"" + richText.at(i) + "\" }";
464 QQmlComponent textComponent(&engine);
465 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
466 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
468 QCOMPARE(textObject->elideMode(), m);
469 QCOMPARE(textObject->width(), 100.);
471 if (m != QQuickText::ElideNone && standard.at(i).contains("<br>"))
472 QVERIFY(textObject->contentWidth() <= textObject->width());
479 void tst_qquicktext::multilineElide_data()
481 QTest::addColumn<QQuickText::TextFormat>("format");
482 QTest::newRow("plain") << QQuickText::PlainText;
483 QTest::newRow("styled") << QQuickText::StyledText;
486 void tst_qquicktext::multilineElide()
488 QFETCH(QQuickText::TextFormat, format);
489 QQuickView *canvas = createView(testFile("multilineelide.qml"));
491 QQuickText *myText = qobject_cast<QQuickText*>(canvas->rootObject());
492 QVERIFY(myText != 0);
493 myText->setTextFormat(format);
495 QCOMPARE(myText->lineCount(), 3);
496 QCOMPARE(myText->truncated(), true);
498 qreal lineHeight = myText->contentHeight() / 3.;
500 // Set a valid height greater than the truncated content height and ensure the line count is
502 myText->setHeight(200);
503 QCOMPARE(myText->lineCount(), 3);
504 QCOMPARE(myText->truncated(), true);
506 // reduce size and ensure fewer lines are drawn
507 myText->setHeight(lineHeight * 2);
508 QCOMPARE(myText->lineCount(), 2);
510 myText->setHeight(lineHeight);
511 QCOMPARE(myText->lineCount(), 1);
513 myText->setHeight(5);
514 QCOMPARE(myText->lineCount(), 1);
516 myText->setHeight(lineHeight * 3);
517 QCOMPARE(myText->lineCount(), 3);
519 // remove max count and show all lines.
520 myText->setHeight(1000);
521 myText->resetMaximumLineCount();
523 QCOMPARE(myText->truncated(), false);
526 myText->setHeight(lineHeight * 2);
527 QCOMPARE(myText->lineCount(), 2);
528 QCOMPARE(myText->truncated(), true);
530 // change line height
531 myText->setLineHeight(1.1);
532 QCOMPARE(myText->lineCount(), 1);
537 void tst_qquicktext::implicitElide_data()
539 QTest::addColumn<QString>("width");
540 QTest::addColumn<QString>("initialText");
541 QTest::addColumn<QString>("text");
543 QTest::newRow("maximum width, empty")
544 << "Math.min(implicitWidth, 100)"
546 QTest::newRow("maximum width, short")
547 << "Math.min(implicitWidth, 100)"
549 QTest::newRow("maximum width, long")
550 << "Math.min(implicitWidth, 100)"
551 << "the quick brown fox jumped over the lazy dog";
552 QTest::newRow("reset width, empty")
553 << "implicitWidth > 100 ? 100 : undefined"
555 QTest::newRow("reset width, short")
556 << "implicitWidth > 100 ? 100 : undefined"
558 QTest::newRow("reset width, long")
559 << "implicitWidth > 100 ? 100 : undefined"
560 << "the quick brown fox jumped over the lazy dog";
563 void tst_qquicktext::implicitElide()
565 QFETCH(QString, width);
566 QFETCH(QString, initialText);
568 QString componentStr =
569 "import QtQuick 2.0\n"
571 "width: " + width + "\n"
572 "text: \"" + initialText + "\"\n"
573 "elide: Text.ElideRight\n"
575 QQmlComponent textComponent(&engine);
576 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
577 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
579 QVERIFY(textObject->contentWidth() <= textObject->width());
581 textObject->setText("the quick brown fox jumped over");
583 QVERIFY(textObject->contentWidth() > 0);
584 QVERIFY(textObject->contentWidth() <= textObject->width());
587 void tst_qquicktext::textFormat()
590 QQmlComponent textComponent(&engine);
591 textComponent.setData("import QtQuick 2.0\nText { text: \"Hello\"; textFormat: Text.RichText }", QUrl::fromLocalFile(""));
592 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
594 QVERIFY(textObject != 0);
595 QVERIFY(textObject->textFormat() == QQuickText::RichText);
597 QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject);
598 QVERIFY(textPrivate != 0);
599 QVERIFY(textPrivate->richText == true);
604 QQmlComponent textComponent(&engine);
605 textComponent.setData("import QtQuick 2.0\nText { text: \"<b>Hello</b>\" }", QUrl::fromLocalFile(""));
606 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
608 QVERIFY(textObject != 0);
609 QVERIFY(textObject->textFormat() == QQuickText::AutoText);
611 QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject);
612 QVERIFY(textPrivate != 0);
613 QVERIFY(textPrivate->styledText == true);
618 QQmlComponent textComponent(&engine);
619 textComponent.setData("import QtQuick 2.0\nText { text: \"<b>Hello</b>\"; textFormat: Text.PlainText }", QUrl::fromLocalFile(""));
620 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
622 QVERIFY(textObject != 0);
623 QVERIFY(textObject->textFormat() == QQuickText::PlainText);
630 void tst_qquicktext::alignments_data()
632 QTest::addColumn<int>("hAlign");
633 QTest::addColumn<int>("vAlign");
634 QTest::addColumn<QString>("expectfile");
636 QTest::newRow("LT") << int(Qt::AlignLeft) << int(Qt::AlignTop) << testFile("alignments_lt.png");
637 QTest::newRow("RT") << int(Qt::AlignRight) << int(Qt::AlignTop) << testFile("alignments_rt.png");
638 QTest::newRow("CT") << int(Qt::AlignHCenter) << int(Qt::AlignTop) << testFile("alignments_ct.png");
640 QTest::newRow("LB") << int(Qt::AlignLeft) << int(Qt::AlignBottom) << testFile("alignments_lb.png");
641 QTest::newRow("RB") << int(Qt::AlignRight) << int(Qt::AlignBottom) << testFile("alignments_rb.png");
642 QTest::newRow("CB") << int(Qt::AlignHCenter) << int(Qt::AlignBottom) << testFile("alignments_cb.png");
644 QTest::newRow("LC") << int(Qt::AlignLeft) << int(Qt::AlignVCenter) << testFile("alignments_lc.png");
645 QTest::newRow("RC") << int(Qt::AlignRight) << int(Qt::AlignVCenter) << testFile("alignments_rc.png");
646 QTest::newRow("CC") << int(Qt::AlignHCenter) << int(Qt::AlignVCenter) << testFile("alignments_cc.png");
650 void tst_qquicktext::alignments()
652 QSKIP("Text alignment pixmap comparison tests will not work with scenegraph");
653 #if (0)// No widgets in scenegraph
656 QFETCH(QString, expectfile);
658 QQuickView *canvas = createView(testFile("alignments.qml"));
660 canvas->requestActivateWindow();
662 QTRY_COMPARE(QGuiApplication::activeWindow(), static_cast<QWidget *>(canvas));
664 QObject *ob = canvas->rootObject();
666 ob->setProperty("horizontalAlignment",hAlign);
667 ob->setProperty("verticalAlignment",vAlign);
668 QTRY_COMPARE(ob->property("running").toBool(),false);
669 QImage actual(canvas->width(), canvas->height(), QImage::Format_RGB32);
670 actual.fill(qRgb(255,255,255));
674 QImage expect(expectfile);
675 if (QGuiApplicationPrivate::graphics_system_name == "raster" || QGuiApplicationPrivate::graphics_system_name == "") {
676 QCOMPARE(actual,expect);
682 //the alignment tests may be trivial o.oa
683 void tst_qquicktext::horizontalAlignment()
685 //test one align each, and then test if two align fails.
687 for (int i = 0; i < standard.size(); i++)
689 for (int j=0; j < horizontalAlignmentmentStrings.size(); j++)
691 QString componentStr = "import QtQuick 2.0\nText { horizontalAlignment: \"" + horizontalAlignmentmentStrings.at(j) + "\"; text: \"" + standard.at(i) + "\" }";
692 QQmlComponent textComponent(&engine);
693 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
694 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
696 QCOMPARE((int)textObject->hAlign(), (int)horizontalAlignmentments.at(j));
702 for (int i = 0; i < richText.size(); i++)
704 for (int j=0; j < horizontalAlignmentmentStrings.size(); j++)
706 QString componentStr = "import QtQuick 2.0\nText { horizontalAlignment: \"" + horizontalAlignmentmentStrings.at(j) + "\"; text: \"" + richText.at(i) + "\" }";
707 QQmlComponent textComponent(&engine);
708 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
709 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
711 QCOMPARE((int)textObject->hAlign(), (int)horizontalAlignmentments.at(j));
719 void tst_qquicktext::horizontalAlignment_RightToLeft()
721 QQuickView *canvas = createView(testFile("horizontalAlignment_RightToLeft.qml"));
722 QQuickText *text = canvas->rootObject()->findChild<QQuickText*>("text");
726 QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(text);
727 QVERIFY(textPrivate != 0);
729 QTRY_VERIFY(textPrivate->layout.lineCount());
731 // implicit alignment should follow the reading direction of RTL text
732 QCOMPARE(text->hAlign(), QQuickText::AlignRight);
733 QCOMPARE(text->effectiveHAlign(), text->hAlign());
734 QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > canvas->width()/2);
736 // explicitly left aligned text
737 text->setHAlign(QQuickText::AlignLeft);
738 QCOMPARE(text->hAlign(), QQuickText::AlignLeft);
739 QCOMPARE(text->effectiveHAlign(), text->hAlign());
740 QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() < canvas->width()/2);
742 // explicitly right aligned text
743 text->setHAlign(QQuickText::AlignRight);
744 QCOMPARE(text->hAlign(), QQuickText::AlignRight);
745 QCOMPARE(text->effectiveHAlign(), text->hAlign());
746 QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > canvas->width()/2);
748 // change to rich text
749 QString textString = text->text();
750 text->setText(QString("<i>") + textString + QString("</i>"));
751 text->setTextFormat(QQuickText::RichText);
754 // implicitly aligned rich text should follow the reading direction of text
755 QCOMPARE(text->hAlign(), QQuickText::AlignRight);
756 QCOMPARE(text->effectiveHAlign(), text->hAlign());
757 QVERIFY(textPrivate->extra.isAllocated());
758 QVERIFY(textPrivate->extra->doc->defaultTextOption().alignment() & Qt::AlignLeft);
760 // explicitly left aligned rich text
761 text->setHAlign(QQuickText::AlignLeft);
762 QCOMPARE(text->hAlign(), QQuickText::AlignLeft);
763 QCOMPARE(text->effectiveHAlign(), text->hAlign());
764 QVERIFY(textPrivate->extra->doc->defaultTextOption().alignment() & Qt::AlignRight);
766 // explicitly right aligned rich text
767 text->setHAlign(QQuickText::AlignRight);
768 QCOMPARE(text->hAlign(), QQuickText::AlignRight);
769 QCOMPARE(text->effectiveHAlign(), text->hAlign());
770 QVERIFY(textPrivate->extra->doc->defaultTextOption().alignment() & Qt::AlignLeft);
772 text->setText(textString);
773 text->setTextFormat(QQuickText::PlainText);
775 // explicitly center aligned
776 text->setHAlign(QQuickText::AlignHCenter);
777 QCOMPARE(text->hAlign(), QQuickText::AlignHCenter);
778 QCOMPARE(text->effectiveHAlign(), text->hAlign());
779 QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() < canvas->width()/2);
780 QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().right() > canvas->width()/2);
782 // reseted alignment should go back to following the text reading direction
784 QCOMPARE(text->hAlign(), QQuickText::AlignRight);
785 QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > canvas->width()/2);
787 // mirror the text item
788 QQuickItemPrivate::get(text)->setLayoutMirror(true);
790 // mirrored implicit alignment should continue to follow the reading direction of the text
791 QCOMPARE(text->hAlign(), QQuickText::AlignRight);
792 QCOMPARE(text->effectiveHAlign(), QQuickText::AlignRight);
793 QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > canvas->width()/2);
795 // mirrored explicitly right aligned behaves as left aligned
796 text->setHAlign(QQuickText::AlignRight);
797 QCOMPARE(text->hAlign(), QQuickText::AlignRight);
798 QCOMPARE(text->effectiveHAlign(), QQuickText::AlignLeft);
799 QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() < canvas->width()/2);
801 // mirrored explicitly left aligned behaves as right aligned
802 text->setHAlign(QQuickText::AlignLeft);
803 QCOMPARE(text->hAlign(), QQuickText::AlignLeft);
804 QCOMPARE(text->effectiveHAlign(), QQuickText::AlignRight);
805 QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > canvas->width()/2);
808 QQuickItemPrivate::get(text)->setLayoutMirror(false);
811 // English text should be implicitly left aligned
812 text->setText("Hello world!");
813 QCOMPARE(text->hAlign(), QQuickText::AlignLeft);
814 QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() < canvas->width()/2);
816 // empty text with implicit alignment follows the system locale-based
817 // keyboard input direction from QInputMethod::inputDirection()
819 QCOMPARE(text->hAlign(), qApp->inputMethod()->inputDirection() == Qt::LeftToRight ?
820 QQuickText::AlignLeft : QQuickText::AlignRight);
821 text->setHAlign(QQuickText::AlignRight);
822 QCOMPARE(text->hAlign(), QQuickText::AlignRight);
826 // alignment of Text with no text set to it
827 QString componentStr = "import QtQuick 2.0\nText {}";
828 QQmlComponent textComponent(&engine);
829 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
830 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
831 QCOMPARE(textObject->hAlign(), qApp->inputMethod()->inputDirection() == Qt::LeftToRight ?
832 QQuickText::AlignLeft : QQuickText::AlignRight);
836 void tst_qquicktext::verticalAlignment()
838 //test one align each, and then test if two align fails.
840 for (int i = 0; i < standard.size(); i++)
842 for (int j=0; j < verticalAlignmentmentStrings.size(); j++)
844 QString componentStr = "import QtQuick 2.0\nText { verticalAlignment: \"" + verticalAlignmentmentStrings.at(j) + "\"; text: \"" + standard.at(i) + "\" }";
845 QQmlComponent textComponent(&engine);
846 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
847 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
849 QVERIFY(textObject != 0);
850 QCOMPARE((int)textObject->vAlign(), (int)verticalAlignmentments.at(j));
856 for (int i = 0; i < richText.size(); i++)
858 for (int j=0; j < verticalAlignmentmentStrings.size(); j++)
860 QString componentStr = "import QtQuick 2.0\nText { verticalAlignment: \"" + verticalAlignmentmentStrings.at(j) + "\"; text: \"" + richText.at(i) + "\" }";
861 QQmlComponent textComponent(&engine);
862 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
863 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
865 QVERIFY(textObject != 0);
866 QCOMPARE((int)textObject->vAlign(), (int)verticalAlignmentments.at(j));
874 void tst_qquicktext::font()
876 //test size, then bold, then italic, then family
878 QString componentStr = "import QtQuick 2.0\nText { font.pointSize: 40; text: \"Hello World\" }";
879 QQmlComponent textComponent(&engine);
880 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
881 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
883 QCOMPARE(textObject->font().pointSize(), 40);
884 QCOMPARE(textObject->font().bold(), false);
885 QCOMPARE(textObject->font().italic(), false);
891 QString componentStr = "import QtQuick 2.0\nText { font.pixelSize: 40; text: \"Hello World\" }";
892 QQmlComponent textComponent(&engine);
893 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
894 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
896 QCOMPARE(textObject->font().pixelSize(), 40);
897 QCOMPARE(textObject->font().bold(), false);
898 QCOMPARE(textObject->font().italic(), false);
904 QString componentStr = "import QtQuick 2.0\nText { font.bold: true; text: \"Hello World\" }";
905 QQmlComponent textComponent(&engine);
906 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
907 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
909 QCOMPARE(textObject->font().bold(), true);
910 QCOMPARE(textObject->font().italic(), false);
916 QString componentStr = "import QtQuick 2.0\nText { font.italic: true; text: \"Hello World\" }";
917 QQmlComponent textComponent(&engine);
918 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
919 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
921 QCOMPARE(textObject->font().italic(), true);
922 QCOMPARE(textObject->font().bold(), false);
928 QString componentStr = "import QtQuick 2.0\nText { font.family: \"Helvetica\"; text: \"Hello World\" }";
929 QQmlComponent textComponent(&engine);
930 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
931 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
933 QCOMPARE(textObject->font().family(), QString("Helvetica"));
934 QCOMPARE(textObject->font().bold(), false);
935 QCOMPARE(textObject->font().italic(), false);
941 QString componentStr = "import QtQuick 2.0\nText { font.family: \"\"; text: \"Hello World\" }";
942 QQmlComponent textComponent(&engine);
943 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
944 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
946 QCOMPARE(textObject->font().family(), QString(""));
952 void tst_qquicktext::style()
955 for (int i = 0; i < styles.size(); i++)
957 QString componentStr = "import QtQuick 2.0\nText { style: \"" + styleStrings.at(i) + "\"; styleColor: \"white\"; text: \"Hello World\" }";
958 QQmlComponent textComponent(&engine);
959 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
960 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
962 QCOMPARE((int)textObject->style(), (int)styles.at(i));
963 QCOMPARE(textObject->styleColor(), QColor("white"));
967 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello World\" }";
968 QQmlComponent textComponent(&engine);
969 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
970 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
972 QRectF brPre = textObject->boundingRect();
973 textObject->setStyle(QQuickText::Outline);
974 QRectF brPost = textObject->boundingRect();
976 QVERIFY(brPre.width() < brPost.width());
977 QVERIFY(brPre.height() < brPost.height());
982 void tst_qquicktext::color()
985 for (int i = 0; i < colorStrings.size(); i++)
987 QString componentStr = "import QtQuick 2.0\nText { color: \"" + colorStrings.at(i) + "\"; text: \"Hello World\" }";
988 QQmlComponent textComponent(&engine);
989 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
990 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
992 QCOMPARE(textObject->color(), QColor(colorStrings.at(i)));
993 QCOMPARE(textObject->styleColor(), QColor("black"));
994 QCOMPARE(textObject->linkColor(), QColor("blue"));
999 for (int i = 0; i < colorStrings.size(); i++)
1001 QString componentStr = "import QtQuick 2.0\nText { styleColor: \"" + colorStrings.at(i) + "\"; text: \"Hello World\" }";
1002 QQmlComponent textComponent(&engine);
1003 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1004 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1006 QCOMPARE(textObject->styleColor(), QColor(colorStrings.at(i)));
1007 // default color to black?
1008 QCOMPARE(textObject->color(), QColor("black"));
1009 QCOMPARE(textObject->linkColor(), QColor("blue"));
1014 for (int i = 0; i < colorStrings.size(); i++)
1016 QString componentStr = "import QtQuick 2.0\nText { linkColor: \"" + colorStrings.at(i) + "\"; text: \"Hello World\" }";
1017 QQmlComponent textComponent(&engine);
1018 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1019 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1021 QCOMPARE(textObject->styleColor(), QColor("black"));
1022 QCOMPARE(textObject->color(), QColor("black"));
1023 QCOMPARE(textObject->linkColor(), QColor(colorStrings.at(i)));
1028 for (int i = 0; i < colorStrings.size(); i++)
1030 for (int j = 0; j < colorStrings.size(); j++)
1032 QString componentStr = "import QtQuick 2.0\nText { "
1033 "color: \"" + colorStrings.at(i) + "\"; "
1034 "styleColor: \"" + colorStrings.at(j) + "\"; "
1035 "linkColor: \"" + colorStrings.at(j) + "\"; "
1036 "text: \"Hello World\" }";
1037 QQmlComponent textComponent(&engine);
1038 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1039 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1041 QCOMPARE(textObject->color(), QColor(colorStrings.at(i)));
1042 QCOMPARE(textObject->styleColor(), QColor(colorStrings.at(j)));
1043 QCOMPARE(textObject->linkColor(), QColor(colorStrings.at(j)));
1049 QString colorStr = "#AA001234";
1050 QColor testColor("#001234");
1051 testColor.setAlpha(170);
1053 QString componentStr = "import QtQuick 2.0\nText { color: \"" + colorStr + "\"; text: \"Hello World\" }";
1054 QQmlComponent textComponent(&engine);
1055 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1056 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1058 QCOMPARE(textObject->color(), testColor);
1062 QString colorStr = "#001234";
1063 QColor testColor(colorStr);
1065 QString componentStr = "import QtQuick 2.0\nText { color: \"" + colorStr + "\"; text: \"Hello World\" }";
1066 QQmlComponent textComponent(&engine);
1067 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1068 QScopedPointer<QObject> object(textComponent.create());
1069 QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
1071 QSignalSpy spy(textObject, SIGNAL(colorChanged()));
1073 QCOMPARE(textObject->color(), testColor);
1074 textObject->setColor(testColor);
1075 QCOMPARE(textObject->color(), testColor);
1076 QCOMPARE(spy.count(), 0);
1078 testColor = QColor("black");
1079 textObject->setColor(testColor);
1080 QCOMPARE(textObject->color(), testColor);
1081 QCOMPARE(spy.count(), 1);
1083 QString colorStr = "#001234";
1084 QColor testColor(colorStr);
1086 QString componentStr = "import QtQuick 2.0\nText { styleColor: \"" + colorStr + "\"; text: \"Hello World\" }";
1087 QQmlComponent textComponent(&engine);
1088 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1089 QScopedPointer<QObject> object(textComponent.create());
1090 QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
1092 QSignalSpy spy(textObject, SIGNAL(styleColorChanged()));
1094 QCOMPARE(textObject->styleColor(), testColor);
1095 textObject->setStyleColor(testColor);
1096 QCOMPARE(textObject->styleColor(), testColor);
1097 QCOMPARE(spy.count(), 0);
1099 testColor = QColor("black");
1100 textObject->setStyleColor(testColor);
1101 QCOMPARE(textObject->styleColor(), testColor);
1102 QCOMPARE(spy.count(), 1);
1104 QString colorStr = "#001234";
1105 QColor testColor(colorStr);
1107 QString componentStr = "import QtQuick 2.0\nText { linkColor: \"" + colorStr + "\"; text: \"Hello World\" }";
1108 QQmlComponent textComponent(&engine);
1109 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1110 QScopedPointer<QObject> object(textComponent.create());
1111 QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
1113 QSignalSpy spy(textObject, SIGNAL(linkColorChanged()));
1115 QCOMPARE(textObject->linkColor(), testColor);
1116 textObject->setLinkColor(testColor);
1117 QCOMPARE(textObject->linkColor(), testColor);
1118 QCOMPARE(spy.count(), 0);
1120 testColor = QColor("black");
1121 textObject->setLinkColor(testColor);
1122 QCOMPARE(textObject->linkColor(), testColor);
1123 QCOMPARE(spy.count(), 1);
1127 void tst_qquicktext::smooth()
1129 for (int i = 0; i < standard.size(); i++)
1132 QString componentStr = "import QtQuick 2.0\nText { smooth: false; text: \"" + standard.at(i) + "\" }";
1133 QQmlComponent textComponent(&engine);
1134 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1135 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1136 QCOMPARE(textObject->smooth(), false);
1141 QString componentStr = "import QtQuick 2.0\nText { text: \"" + standard.at(i) + "\" }";
1142 QQmlComponent textComponent(&engine);
1143 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1144 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1145 QCOMPARE(textObject->smooth(), true);
1150 for (int i = 0; i < richText.size(); i++)
1153 QString componentStr = "import QtQuick 2.0\nText { smooth: false; text: \"" + richText.at(i) + "\" }";
1154 QQmlComponent textComponent(&engine);
1155 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1156 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1157 QCOMPARE(textObject->smooth(), false);
1162 QString componentStr = "import QtQuick 2.0\nText { text: \"" + richText.at(i) + "\" }";
1163 QQmlComponent textComponent(&engine);
1164 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1165 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1166 QCOMPARE(textObject->smooth(), true);
1173 void tst_qquicktext::weight()
1176 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
1177 QQmlComponent textComponent(&engine);
1178 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1179 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1181 QVERIFY(textObject != 0);
1182 QCOMPARE((int)textObject->font().weight(), (int)QQuickFontValueType::Normal);
1187 QString componentStr = "import QtQuick 2.0\nText { font.weight: \"Bold\"; text: \"Hello world!\" }";
1188 QQmlComponent textComponent(&engine);
1189 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1190 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1192 QVERIFY(textObject != 0);
1193 QCOMPARE((int)textObject->font().weight(), (int)QQuickFontValueType::Bold);
1199 void tst_qquicktext::underline()
1202 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
1203 QQmlComponent textComponent(&engine);
1204 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1205 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1207 QVERIFY(textObject != 0);
1208 QCOMPARE(textObject->font().underline(), false);
1213 QString componentStr = "import QtQuick 2.0\nText { font.underline: true; text: \"Hello world!\" }";
1214 QQmlComponent textComponent(&engine);
1215 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1216 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1218 QVERIFY(textObject != 0);
1219 QCOMPARE(textObject->font().underline(), true);
1225 void tst_qquicktext::overline()
1228 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
1229 QQmlComponent textComponent(&engine);
1230 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1231 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1233 QVERIFY(textObject != 0);
1234 QCOMPARE(textObject->font().overline(), false);
1239 QString componentStr = "import QtQuick 2.0\nText { font.overline: true; text: \"Hello world!\" }";
1240 QQmlComponent textComponent(&engine);
1241 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1242 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1244 QVERIFY(textObject != 0);
1245 QCOMPARE(textObject->font().overline(), true);
1251 void tst_qquicktext::strikeout()
1254 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
1255 QQmlComponent textComponent(&engine);
1256 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1257 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1259 QVERIFY(textObject != 0);
1260 QCOMPARE(textObject->font().strikeOut(), false);
1265 QString componentStr = "import QtQuick 2.0\nText { font.strikeout: true; text: \"Hello world!\" }";
1266 QQmlComponent textComponent(&engine);
1267 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1268 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1270 QVERIFY(textObject != 0);
1271 QCOMPARE(textObject->font().strikeOut(), true);
1277 void tst_qquicktext::capitalization()
1280 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
1281 QQmlComponent textComponent(&engine);
1282 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1283 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1285 QVERIFY(textObject != 0);
1286 QCOMPARE((int)textObject->font().capitalization(), (int)QQuickFontValueType::MixedCase);
1291 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.capitalization: \"AllUppercase\" }";
1292 QQmlComponent textComponent(&engine);
1293 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1294 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1296 QVERIFY(textObject != 0);
1297 QCOMPARE((int)textObject->font().capitalization(), (int)QQuickFontValueType::AllUppercase);
1302 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.capitalization: \"AllLowercase\" }";
1303 QQmlComponent textComponent(&engine);
1304 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1305 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1307 QVERIFY(textObject != 0);
1308 QCOMPARE((int)textObject->font().capitalization(), (int)QQuickFontValueType::AllLowercase);
1313 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.capitalization: \"SmallCaps\" }";
1314 QQmlComponent textComponent(&engine);
1315 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1316 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1318 QVERIFY(textObject != 0);
1319 QCOMPARE((int)textObject->font().capitalization(), (int)QQuickFontValueType::SmallCaps);
1324 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.capitalization: \"Capitalize\" }";
1325 QQmlComponent textComponent(&engine);
1326 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1327 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1329 QVERIFY(textObject != 0);
1330 QCOMPARE((int)textObject->font().capitalization(), (int)QQuickFontValueType::Capitalize);
1336 void tst_qquicktext::letterSpacing()
1339 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
1340 QQmlComponent textComponent(&engine);
1341 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1342 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1344 QVERIFY(textObject != 0);
1345 QCOMPARE(textObject->font().letterSpacing(), 0.0);
1350 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.letterSpacing: -2 }";
1351 QQmlComponent textComponent(&engine);
1352 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1353 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1355 QVERIFY(textObject != 0);
1356 QCOMPARE(textObject->font().letterSpacing(), -2.);
1361 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.letterSpacing: 3 }";
1362 QQmlComponent textComponent(&engine);
1363 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1364 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1366 QVERIFY(textObject != 0);
1367 QCOMPARE(textObject->font().letterSpacing(), 3.);
1373 void tst_qquicktext::wordSpacing()
1376 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
1377 QQmlComponent textComponent(&engine);
1378 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1379 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1381 QVERIFY(textObject != 0);
1382 QCOMPARE(textObject->font().wordSpacing(), 0.0);
1387 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.wordSpacing: -50 }";
1388 QQmlComponent textComponent(&engine);
1389 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1390 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1392 QVERIFY(textObject != 0);
1393 QCOMPARE(textObject->font().wordSpacing(), -50.);
1398 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.wordSpacing: 200 }";
1399 QQmlComponent textComponent(&engine);
1400 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1401 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1403 QVERIFY(textObject != 0);
1404 QCOMPARE(textObject->font().wordSpacing(), 200.);
1413 class EventSender : public QQuickItem
1416 void sendEvent(QMouseEvent *event) {
1417 if (event->type() == QEvent::MouseButtonPress)
1418 mousePressEvent(event);
1419 else if (event->type() == QEvent::MouseButtonRelease)
1420 mouseReleaseEvent(event);
1422 qWarning() << "Trying to send unsupported event type";
1426 class LinkTest : public QObject
1435 void linkClicked(QString l) { link = l; }
1438 void tst_qquicktext::clickLink()
1441 QString componentStr = "import QtQuick 2.0\nText { text: \"<a href=\\\"http://qt.nokia.com\\\">Hello world!</a>\" }";
1442 QQmlComponent textComponent(&engine);
1443 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1444 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1446 QVERIFY(textObject != 0);
1449 QObject::connect(textObject, SIGNAL(linkActivated(QString)), &test, SLOT(linkClicked(QString)));
1452 QMouseEvent me(QEvent::MouseButtonPress,QPointF(textObject->x()/2, textObject->y()/2), Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
1453 static_cast<EventSender*>(static_cast<QQuickItem*>(textObject))->sendEvent(&me);
1458 QMouseEvent me(QEvent::MouseButtonRelease,QPointF(textObject->x()/2, textObject->y()/2), Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
1459 static_cast<EventSender*>(static_cast<QQuickItem*>(textObject))->sendEvent(&me);
1464 QCOMPARE(test.link, QLatin1String("http://qt.nokia.com"));
1470 void tst_qquicktext::baseUrl()
1472 QUrl localUrl("file:///tests/text.qml");
1473 QUrl remoteUrl("http://qt.nokia.com/test.qml");
1475 QQmlComponent textComponent(&engine);
1476 textComponent.setData("import QtQuick 2.0\n Text {}", localUrl);
1477 QQuickText *textObject = qobject_cast<QQuickText *>(textComponent.create());
1479 QCOMPARE(textObject->baseUrl(), localUrl);
1481 QSignalSpy spy(textObject, SIGNAL(baseUrlChanged()));
1483 textObject->setBaseUrl(localUrl);
1484 QCOMPARE(textObject->baseUrl(), localUrl);
1485 QCOMPARE(spy.count(), 0);
1487 textObject->setBaseUrl(remoteUrl);
1488 QCOMPARE(textObject->baseUrl(), remoteUrl);
1489 QCOMPARE(spy.count(), 1);
1491 textObject->resetBaseUrl();
1492 QCOMPARE(textObject->baseUrl(), localUrl);
1493 QCOMPARE(spy.count(), 2);
1496 void tst_qquicktext::embeddedImages_data()
1498 QTest::addColumn<QUrl>("qmlfile");
1499 QTest::addColumn<QString>("error");
1500 QTest::newRow("local") << testFileUrl("embeddedImagesLocal.qml") << "";
1501 QTest::newRow("local-error") << testFileUrl("embeddedImagesLocalError.qml")
1502 << testFileUrl("embeddedImagesLocalError.qml").toString()+":3:1: QML Text: Cannot open: " + testFileUrl("http/notexists.png").toString();
1503 QTest::newRow("local") << testFileUrl("embeddedImagesLocalRelative.qml") << "";
1504 QTest::newRow("remote") << testFileUrl("embeddedImagesRemote.qml") << "";
1505 QTest::newRow("remote-error") << testFileUrl("embeddedImagesRemoteError.qml")
1506 << testFileUrl("embeddedImagesRemoteError.qml").toString()+":3:1: QML Text: Error downloading http://127.0.0.1:14453/notexists.png - server replied: Not found";
1507 QTest::newRow("remote") << testFileUrl("embeddedImagesRemoteRelative.qml") << "";
1510 void tst_qquicktext::embeddedImages()
1514 QFETCH(QUrl, qmlfile);
1515 QFETCH(QString, error);
1517 TestHTTPServer server(14453);
1518 server.serveDirectory(testFile("http"));
1520 if (!error.isEmpty())
1521 QTest::ignoreMessage(QtWarningMsg, error.toLatin1());
1523 QQmlComponent textComponent(&engine, qmlfile);
1524 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1526 QVERIFY(textObject != 0);
1528 QTRY_COMPARE(textObject->resourcesLoading(), 0);
1530 QPixmap pm(testFile("http/exists.png"));
1531 if (error.isEmpty()) {
1532 QCOMPARE(textObject->width(), double(pm.width()));
1533 QCOMPARE(textObject->height(), double(pm.height()));
1535 QVERIFY(16 != pm.width()); // check test is effective
1536 QCOMPARE(textObject->width(), 16.0); // default size of QTextDocument broken image icon
1537 QCOMPARE(textObject->height(), 16.0);
1543 void tst_qquicktext::lineCount()
1545 QQuickView *canvas = createView(testFile("lineCount.qml"));
1547 QQuickText *myText = canvas->rootObject()->findChild<QQuickText*>("myText");
1548 QVERIFY(myText != 0);
1550 QVERIFY(myText->lineCount() > 1);
1551 QVERIFY(!myText->truncated());
1552 QCOMPARE(myText->maximumLineCount(), INT_MAX);
1554 myText->setMaximumLineCount(2);
1555 QCOMPARE(myText->lineCount(), 2);
1556 QCOMPARE(myText->truncated(), true);
1557 QCOMPARE(myText->maximumLineCount(), 2);
1559 myText->resetMaximumLineCount();
1560 QCOMPARE(myText->maximumLineCount(), INT_MAX);
1561 QCOMPARE(myText->truncated(), false);
1563 myText->setElideMode(QQuickText::ElideRight);
1564 myText->setMaximumLineCount(2);
1565 QCOMPARE(myText->lineCount(), 2);
1566 QCOMPARE(myText->truncated(), true);
1567 QCOMPARE(myText->maximumLineCount(), 2);
1572 void tst_qquicktext::lineHeight()
1574 QQuickView *canvas = createView(testFile("lineHeight.qml"));
1576 QQuickText *myText = canvas->rootObject()->findChild<QQuickText*>("myText");
1577 QVERIFY(myText != 0);
1579 QVERIFY(myText->lineHeight() == 1);
1580 QVERIFY(myText->lineHeightMode() == QQuickText::ProportionalHeight);
1582 qreal h = myText->height();
1583 myText->setLineHeight(1.5);
1584 QCOMPARE(myText->height(), qreal(qCeil(h * 1.5)));
1586 myText->setLineHeightMode(QQuickText::FixedHeight);
1587 myText->setLineHeight(20);
1588 QCOMPARE(myText->height(), myText->lineCount() * 20.0);
1590 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.");
1591 myText->setLineHeightMode(QQuickText::ProportionalHeight);
1592 myText->setLineHeight(1.0);
1594 qreal h2 = myText->height();
1595 myText->setLineHeight(2.0);
1596 QVERIFY(myText->height() == h2 * 2.0);
1598 myText->setLineHeightMode(QQuickText::FixedHeight);
1599 myText->setLineHeight(10);
1600 QCOMPARE(myText->height(), myText->lineCount() * 10.0);
1605 void tst_qquicktext::implicitSize_data()
1607 QTest::addColumn<QString>("text");
1608 QTest::addColumn<QString>("width");
1609 QTest::addColumn<QString>("wrap");
1610 QTest::addColumn<QString>("elide");
1611 QTest::addColumn<QString>("format");
1612 QTest::newRow("plain") << "The quick red fox jumped over the lazy brown dog" << "50" << "Text.NoWrap" << "Text.ElideNone" << "Text.PlainText";
1613 QTest::newRow("richtext") << "<b>The quick red fox jumped over the lazy brown dog</b>" <<" 50" << "Text.NoWrap" << "Text.ElideNone" << "Text.RichText";
1614 QTest::newRow("styledtext") << "<b>The quick red fox jumped over the lazy brown dog</b>" <<" 50" << "Text.NoWrap" << "Text.ElideNone" << "Text.StyledText";
1615 QTest::newRow("plain, 0 width") << "The quick red fox jumped over the lazy brown dog" << "0" << "Text.NoWrap" << "Text.ElideNone" << "Text.PlainText";
1616 QTest::newRow("plain, elide") << "The quick red fox jumped over the lazy brown dog" << "50" << "Text.NoWrap" << "Text.ElideRight" << "Text.PlainText";
1617 QTest::newRow("plain, 0 width, elide") << "The quick red fox jumped over the lazy brown dog" << "0" << "Text.NoWrap" << "Text.ElideRight" << "Text.PlainText";
1618 QTest::newRow("richtext, 0 width") << "<b>The quick red fox jumped over the lazy brown dog</b>" <<" 0" << "Text.NoWrap" << "Text.ElideNone" << "Text.RichText";
1619 QTest::newRow("styledtext, 0 width") << "<b>The quick red fox jumped over the lazy brown dog</b>" <<" 0" << "Text.NoWrap" << "Text.ElideNone" << "Text.StyledText";
1620 QTest::newRow("plain_wrap") << "The quick red fox jumped over the lazy brown dog" << "50" << "Text.Wrap" << "Text.ElideNone" << "Text.PlainText";
1621 QTest::newRow("richtext_wrap") << "<b>The quick red fox jumped over the lazy brown dog</b>" << "50" << "Text.Wrap" << "Text.ElideNone" << "Text.RichText";
1622 QTest::newRow("styledtext_wrap") << "<b>The quick red fox jumped over the lazy brown dog</b>" << "50" << "Text.Wrap" << "Text.ElideNone" << "Text.StyledText";
1623 QTest::newRow("plain_wrap, 0 width") << "The quick red fox jumped over the lazy brown dog" << "0" << "Text.Wrap" << "Text.ElideNone" << "Text.PlainText";
1624 QTest::newRow("plain_wrap, elide") << "The quick red fox jumped over the lazy brown dog" << "50" << "Text.Wrap" << "Text.ElideRight" << "Text.PlainText";
1625 QTest::newRow("plain_wrap, 0 width, elide") << "The quick red fox jumped over the lazy brown dog" << "0" << "Text.Wrap" << "Text.ElideRight" << "Text.PlainText";
1626 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";
1627 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";
1630 void tst_qquicktext::implicitSize()
1632 QFETCH(QString, text);
1633 QFETCH(QString, width);
1634 QFETCH(QString, format);
1635 QFETCH(QString, wrap);
1636 QFETCH(QString, elide);
1637 QString componentStr = "import QtQuick 2.0\nText { "
1638 "property real iWidth: implicitWidth; "
1639 "text: \"" + text + "\"; "
1640 "width: " + width + "; "
1641 "textFormat: " + format + "; "
1642 "wrapMode: " + wrap + "; "
1643 "elide: " + elide + "; "
1644 "maximumLineCount: 2 }";
1645 QQmlComponent textComponent(&engine);
1646 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1647 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1649 QVERIFY(textObject->width() < textObject->implicitWidth());
1650 QVERIFY(textObject->height() == textObject->implicitHeight());
1651 QCOMPARE(textObject->property("iWidth").toReal(), textObject->implicitWidth());
1653 textObject->resetWidth();
1654 QVERIFY(textObject->width() == textObject->implicitWidth());
1655 QVERIFY(textObject->height() == textObject->implicitHeight());
1660 void tst_qquicktext::contentSize()
1662 QString componentStr = "import QtQuick 2.0\nText { width: 75; height: 16; font.pixelSize: 10 }";
1663 QQmlComponent textComponent(&engine);
1664 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1665 QScopedPointer<QObject> object(textComponent.create());
1666 QQuickText *textObject = qobject_cast<QQuickText *>(object.data());
1668 QSignalSpy spy(textObject, SIGNAL(contentSizeChanged()));
1670 textObject->setText("The quick red fox jumped over the lazy brown dog");
1672 QVERIFY(textObject->contentWidth() > textObject->width());
1673 QVERIFY(textObject->contentHeight() < textObject->height());
1674 QCOMPARE(spy.count(), 1);
1676 textObject->setWrapMode(QQuickText::WordWrap);
1677 QVERIFY(textObject->contentWidth() <= textObject->width());
1678 QVERIFY(textObject->contentHeight() > textObject->height());
1679 QCOMPARE(spy.count(), 2);
1681 textObject->setElideMode(QQuickText::ElideRight);
1682 QVERIFY(textObject->contentWidth() <= textObject->width());
1683 QVERIFY(textObject->contentHeight() < textObject->height());
1684 QCOMPARE(spy.count(), 3);
1686 qreal elidedWidth = textObject->contentWidth();
1688 textObject->setText("The quickredfoxjumpedoverthe lazy brown dog");
1689 QVERIFY(textObject->contentWidth() <= textObject->width());
1690 QVERIFY(textObject->contentHeight() < textObject->height());
1691 // this text probably won't have the same elided width, but it's not guaranteed.
1692 if (textObject->contentWidth() != elidedWidth)
1693 QCOMPARE(spy.count(), ++spyCount);
1695 QCOMPARE(spy.count(), spyCount);
1697 textObject->setElideMode(QQuickText::ElideNone);
1698 QVERIFY(textObject->contentWidth() > textObject->width());
1699 QVERIFY(textObject->contentHeight() > textObject->height());
1700 QCOMPARE(spy.count(), ++spyCount);
1703 void tst_qquicktext::implicitSizeBinding_data()
1705 implicitSize_data();
1708 void tst_qquicktext::implicitSizeBinding()
1710 QFETCH(QString, text);
1711 QFETCH(QString, wrap);
1712 QFETCH(QString, format);
1713 QString componentStr = "import QtQuick 2.0\nText { text: \"" + text + "\"; width: implicitWidth; height: implicitHeight; wrapMode: " + wrap + "; textFormat: " + format + " }";
1715 QQmlComponent textComponent(&engine);
1716 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1717 QScopedPointer<QObject> object(textComponent.create());
1718 QQuickText *textObject = qobject_cast<QQuickText *>(object.data());
1720 QCOMPARE(textObject->width(), textObject->implicitWidth());
1721 QCOMPARE(textObject->height(), textObject->implicitHeight());
1723 textObject->resetWidth();
1724 QCOMPARE(textObject->width(), textObject->implicitWidth());
1725 QCOMPARE(textObject->height(), textObject->implicitHeight());
1727 textObject->resetHeight();
1728 QCOMPARE(textObject->width(), textObject->implicitWidth());
1729 QCOMPARE(textObject->height(), textObject->implicitHeight());
1732 void tst_qquicktext::boundingRect_data()
1734 QTest::addColumn<QString>("format");
1735 QTest::newRow("PlainText") << "Text.PlainText";
1736 QTest::newRow("StyledText") << "Text.StyledText";
1737 QTest::newRow("RichText") << "Text.RichText";
1740 void tst_qquicktext::boundingRect()
1742 QFETCH(QString, format);
1744 QQmlComponent component(&engine);
1745 component.setData("import QtQuick 2.0\n Text { textFormat:" + format.toUtf8() + "}", QUrl());
1746 QScopedPointer<QObject> object(component.create());
1747 QQuickText *text = qobject_cast<QQuickText *>(object.data());
1750 QCOMPARE(text->boundingRect().x(), qreal(0));
1751 QCOMPARE(text->boundingRect().y(), qreal(0));
1752 QCOMPARE(text->boundingRect().width(), qreal(0));
1753 QCOMPARE(text->boundingRect().height(), qreal(qCeil(QFontMetricsF(text->font()).height())));
1755 text->setText("Hello World");
1757 QTextLayout layout(text->text());
1758 layout.setFont(text->font());
1760 if (!qmlDisableDistanceField()) {
1762 option.setUseDesignMetrics(true);
1763 layout.setTextOption(option);
1765 layout.beginLayout();
1766 QTextLine line = layout.createLine();
1769 QCOMPARE(text->boundingRect().x(), qreal(0));
1770 QCOMPARE(text->boundingRect().y(), qreal(0));
1771 QCOMPARE(text->boundingRect().width(), line.naturalTextWidth());
1772 QCOMPARE(text->boundingRect().height(), line.height());
1774 // the size of the bounding rect shouldn't be bounded by the size of item.
1775 text->setWidth(text->width() / 2);
1776 QCOMPARE(text->boundingRect().x(), qreal(0));
1777 QCOMPARE(text->boundingRect().y(), qreal(0));
1778 QCOMPARE(text->boundingRect().width(), line.naturalTextWidth());
1779 QCOMPARE(text->boundingRect().height(), line.height());
1781 text->setHeight(text->height() * 2);
1782 QCOMPARE(text->boundingRect().x(), qreal(0));
1783 QCOMPARE(text->boundingRect().y(), qreal(0));
1784 QCOMPARE(text->boundingRect().width(), line.naturalTextWidth());
1785 QCOMPARE(text->boundingRect().height(), line.height());
1787 text->setHAlign(QQuickText::AlignRight);
1788 QCOMPARE(text->boundingRect().x(), text->width() - line.naturalTextWidth());
1789 QCOMPARE(text->boundingRect().y(), qreal(0));
1790 QCOMPARE(text->boundingRect().width(), line.naturalTextWidth());
1791 QCOMPARE(text->boundingRect().height(), line.height());
1793 text->setWrapMode(QQuickText::Wrap);
1794 QCOMPARE(text->boundingRect().right(), text->width());
1795 QCOMPARE(text->boundingRect().y(), qreal(0));
1796 QVERIFY(text->boundingRect().width() < line.naturalTextWidth());
1797 QVERIFY(text->boundingRect().height() > line.height());
1799 text->setVAlign(QQuickText::AlignBottom);
1800 QCOMPARE(text->boundingRect().right(), text->width());
1801 QCOMPARE(text->boundingRect().bottom(), text->height());
1802 QVERIFY(text->boundingRect().width() < line.naturalTextWidth());
1803 QVERIFY(text->boundingRect().height() > line.height());
1806 void tst_qquicktext::clipRect()
1808 QQmlComponent component(&engine);
1809 component.setData("import QtQuick 2.0\n Text {}", QUrl());
1810 QScopedPointer<QObject> object(component.create());
1811 QQuickText *text = qobject_cast<QQuickText *>(object.data());
1815 layout.setFont(text->font());
1817 QCOMPARE(text->clipRect().x(), qreal(0));
1818 QCOMPARE(text->clipRect().y(), qreal(0));
1819 QCOMPARE(text->clipRect().width(), text->width());
1820 QCOMPARE(text->clipRect().height(), text->height());
1822 text->setText("Hello World");
1824 QCOMPARE(text->clipRect().x(), qreal(0));
1825 QCOMPARE(text->clipRect().y(), qreal(0));
1826 QCOMPARE(text->clipRect().width(), text->width());
1827 QCOMPARE(text->clipRect().height(), text->height());
1829 // Clip rect follows the item not content dimensions.
1830 text->setWidth(text->width() / 2);
1831 QCOMPARE(text->clipRect().x(), qreal(0));
1832 QCOMPARE(text->clipRect().y(), qreal(0));
1833 QCOMPARE(text->clipRect().width(), text->width());
1834 QCOMPARE(text->clipRect().height(), text->height());
1836 text->setHeight(text->height() * 2);
1837 QCOMPARE(text->clipRect().x(), qreal(0));
1838 QCOMPARE(text->clipRect().y(), qreal(0));
1839 QCOMPARE(text->clipRect().width(), text->width());
1840 QCOMPARE(text->clipRect().height(), text->height());
1842 // Setting a style adds a small amount of padding to the clip rect.
1843 text->setStyle(QQuickText::Outline);
1844 QCOMPARE(text->clipRect().x(), qreal(-1));
1845 QCOMPARE(text->clipRect().y(), qreal(0));
1846 QCOMPARE(text->clipRect().width(), text->width() + 2);
1847 QCOMPARE(text->clipRect().height(), text->height() + 2);
1850 void tst_qquicktext::lineLaidOut()
1852 QQuickView *canvas = createView(testFile("lineLayout.qml"));
1854 QQuickText *myText = canvas->rootObject()->findChild<QQuickText*>("myText");
1855 QVERIFY(myText != 0);
1857 QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(myText);
1858 QVERIFY(textPrivate != 0);
1860 QVERIFY(!textPrivate->extra.isAllocated());
1862 #if defined(Q_OS_MAC)
1863 QVERIFY(myText->lineCount() == textPrivate->linesRects.count());
1866 for (int i = 0; i < textPrivate->layout.lineCount(); ++i) {
1867 QRectF r = textPrivate->layout.lineAt(i).rect();
1868 QVERIFY(r.width() == i * 15);
1870 QVERIFY(r.x() == r.width() + 30);
1872 QVERIFY(r.x() == r.width() * 2 + 60);
1873 QVERIFY(r.height() == 20);
1880 void tst_qquicktext::imgTagsBaseUrl_data()
1882 QTest::addColumn<QUrl>("src");
1883 QTest::addColumn<QUrl>("baseUrl");
1884 QTest::addColumn<QUrl>("contextUrl");
1885 QTest::addColumn<qreal>("imgHeight");
1887 QTest::newRow("absolute local")
1888 << testFileUrl("images/heart200.png")
1892 QTest::newRow("relative local context 1")
1893 << QUrl("images/heart200.png")
1895 << testFileUrl("/app.qml")
1897 QTest::newRow("relative local context 2")
1898 << QUrl("heart200.png")
1900 << testFileUrl("images/app.qml")
1902 QTest::newRow("relative local base 1")
1903 << QUrl("images/heart200.png")
1905 << testFileUrl("nonexistant/app.qml")
1907 QTest::newRow("relative local base 2")
1908 << QUrl("heart200.png")
1909 << testFileUrl("images/")
1910 << testFileUrl("nonexistant/app.qml")
1912 QTest::newRow("base relative to local context")
1913 << QUrl("heart200.png")
1914 << testFileUrl("images/")
1915 << testFileUrl("/app.qml")
1918 QTest::newRow("absolute remote")
1919 << QUrl("http://127.0.0.1:14453/images/heart200.png")
1923 QTest::newRow("relative remote base 1")
1924 << QUrl("images/heart200.png")
1925 << QUrl("http://127.0.0.1:14453/")
1926 << testFileUrl("nonexistant/app.qml")
1928 QTest::newRow("relative remote base 2")
1929 << QUrl("heart200.png")
1930 << QUrl("http://127.0.0.1:14453/images/")
1931 << testFileUrl("nonexistant/app.qml")
1935 void tst_qquicktext::imgTagsBaseUrl()
1938 QFETCH(QUrl, baseUrl);
1939 QFETCH(QUrl, contextUrl);
1940 QFETCH(qreal, imgHeight);
1942 TestHTTPServer server(14453);
1943 server.serveDirectory(testFile(""));
1945 QByteArray baseUrlFragment;
1946 if (!baseUrl.isEmpty())
1947 baseUrlFragment = "; baseUrl: \"" + baseUrl.toEncoded() + "\"";
1948 QByteArray componentStr = "import QtQuick 2.0\nText { text: \"This is a test <img src=\\\"" + src.toEncoded() + "\\\">\"" + baseUrlFragment + " }";
1950 QQmlComponent component(&engine);
1951 component.setData(componentStr, contextUrl);
1952 QScopedPointer<QObject> object(component.create());
1953 QQuickText *textObject = qobject_cast<QQuickText *>(object.data());
1954 QVERIFY(textObject);
1956 QCoreApplication::processEvents();
1958 QTRY_COMPARE(textObject->height(), imgHeight);
1961 void tst_qquicktext::imgTagsAlign_data()
1963 QTest::addColumn<QString>("src");
1964 QTest::addColumn<int>("imgHeight");
1965 QTest::addColumn<QString>("align");
1966 QTest::newRow("heart-bottom") << "data/images/heart200.png" << 181 << "bottom";
1967 QTest::newRow("heart-middle") << "data/images/heart200.png" << 181 << "middle";
1968 QTest::newRow("heart-top") << "data/images/heart200.png" << 181 << "top";
1969 QTest::newRow("starfish-bottom") << "data/images/starfish_2.png" << 217 << "bottom";
1970 QTest::newRow("starfish-middle") << "data/images/starfish_2.png" << 217 << "middle";
1971 QTest::newRow("starfish-top") << "data/images/starfish_2.png" << 217 << "top";
1974 void tst_qquicktext::imgTagsAlign()
1976 QFETCH(QString, src);
1977 QFETCH(int, imgHeight);
1978 QFETCH(QString, align);
1979 QString componentStr = "import QtQuick 2.0\nText { text: \"This is a test <img src=\\\"" + src + "\\\" align=\\\"" + align + "\\\"> of image.\" }";
1980 QQmlComponent textComponent(&engine);
1981 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1982 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1984 QVERIFY(textObject != 0);
1985 QVERIFY(textObject->height() == imgHeight);
1987 QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject);
1988 QVERIFY(textPrivate != 0);
1990 QRectF br = textPrivate->layout.boundingRect();
1991 if (align == "bottom")
1992 QVERIFY(br.y() == imgHeight - br.height());
1993 else if (align == "middle")
1994 QVERIFY(br.y() == imgHeight / 2.0 - br.height() / 2.0);
1995 else if (align == "top")
1996 QVERIFY(br.y() == 0);
2001 void tst_qquicktext::imgTagsMultipleImages()
2003 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\\\">.\" }";
2005 QQmlComponent textComponent(&engine);
2006 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
2007 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
2009 QVERIFY(textObject != 0);
2010 QVERIFY(textObject->height() == 85);
2012 QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject);
2013 QVERIFY(textPrivate != 0);
2014 QVERIFY(textPrivate->visibleImgTags.count() == 2);
2019 void tst_qquicktext::imgTagsElide()
2021 QQuickView *canvas = createView(testFile("imgTagsElide.qml"));
2022 QQuickText *myText = canvas->rootObject()->findChild<QQuickText*>("myText");
2023 QVERIFY(myText != 0);
2025 QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(myText);
2026 QVERIFY(textPrivate != 0);
2027 QVERIFY(textPrivate->visibleImgTags.count() == 0);
2028 myText->setMaximumLineCount(20);
2029 QTRY_VERIFY(textPrivate->visibleImgTags.count() == 1);
2035 void tst_qquicktext::imgTagsUpdates()
2037 QQuickView *canvas = createView(testFile("imgTagsUpdates.qml"));
2038 QQuickText *myText = canvas->rootObject()->findChild<QQuickText*>("myText");
2039 QVERIFY(myText != 0);
2041 QSignalSpy spy(myText, SIGNAL(contentSizeChanged()));
2043 QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(myText);
2044 QVERIFY(textPrivate != 0);
2046 myText->setText("This is a heart<img src=\"images/heart200.png\">.");
2047 QVERIFY(textPrivate->visibleImgTags.count() == 1);
2048 QVERIFY(spy.count() == 1);
2050 myText->setMaximumLineCount(2);
2051 myText->setText("This is another heart<img src=\"images/heart200.png\">.");
2052 QTRY_VERIFY(textPrivate->visibleImgTags.count() == 1);
2054 // if maximumLineCount is set and the img tag doesn't have an explicit size
2055 // we relayout twice.
2056 QVERIFY(spy.count() == 3);
2062 void tst_qquicktext::imgTagsError()
2064 QString componentStr = "import QtQuick 2.0\nText { text: \"This is a starfish<img src=\\\"data/images/starfish_2.pn\\\" width=\\\"60\\\" height=\\\"60\\\">.\" }";
2066 QQmlComponent textComponent(&engine);
2067 QTest::ignoreMessage(QtWarningMsg, "file::2:1: QML Text: Cannot open: file:data/images/starfish_2.pn");
2068 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
2069 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
2071 QVERIFY(textObject != 0);
2075 void tst_qquicktext::fontSizeMode_data()
2077 QTest::addColumn<QString>("text");
2078 QTest::newRow("plain") << "The quick red fox jumped over the lazy brown dog";
2079 QTest::newRow("styled") << "<b>The quick red fox jumped over the lazy brown dog</b>";
2082 void tst_qquicktext::fontSizeMode()
2084 QFETCH(QString, text);
2086 QScopedPointer<QQuickView> canvas(createView(testFile("fontSizeMode.qml")));
2089 QQuickText *myText = canvas->rootObject()->findChild<QQuickText*>("myText");
2090 QVERIFY(myText != 0);
2092 myText->setText(text);
2093 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2095 qreal originalWidth = myText->contentWidth();
2096 qreal originalHeight = myText->contentHeight();
2098 // The original text unwrapped should exceed the width of the item.
2099 QVERIFY(originalWidth > myText->width());
2100 QVERIFY(originalHeight < myText->height());
2102 QFont font = myText->font();
2103 font.setPixelSize(64);
2105 myText->setFont(font);
2106 myText->setFontSizeMode(QQuickText::HorizontalFit);
2107 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2108 // Font size reduced to fit within the width of the item.
2109 qreal horizontalFitWidth = myText->contentWidth();
2110 qreal horizontalFitHeight = myText->contentHeight();
2111 QVERIFY(horizontalFitWidth <= myText->width() + 2); // rounding
2112 QVERIFY(horizontalFitHeight <= myText->height() + 2);
2114 // Elide won't affect the size with HorizontalFit.
2115 myText->setElideMode(QQuickText::ElideRight);
2116 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2117 QVERIFY(!myText->truncated());
2118 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2119 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2121 myText->setElideMode(QQuickText::ElideLeft);
2122 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2123 QVERIFY(!myText->truncated());
2124 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2125 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2127 myText->setElideMode(QQuickText::ElideMiddle);
2128 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2129 QVERIFY(!myText->truncated());
2130 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2131 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2133 myText->setElideMode(QQuickText::ElideNone);
2134 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2136 myText->setFontSizeMode(QQuickText::VerticalFit);
2137 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2138 // Font size increased to fill the height of the item.
2139 qreal verticalFitHeight = myText->contentHeight();
2140 QVERIFY(myText->contentWidth() > myText->width());
2141 QVERIFY(verticalFitHeight <= myText->height() + 2);
2142 QVERIFY(verticalFitHeight > originalHeight);
2144 // Elide won't affect the height of a single line with VerticalFit but will crop the width.
2145 myText->setElideMode(QQuickText::ElideRight);
2146 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2147 QVERIFY(myText->truncated());
2148 QVERIFY(myText->contentWidth() <= myText->width() + 2);
2149 QCOMPARE(myText->contentHeight(), verticalFitHeight);
2151 myText->setElideMode(QQuickText::ElideLeft);
2152 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2153 QVERIFY(myText->truncated());
2154 QVERIFY(myText->contentWidth() <= myText->width() + 2);
2155 QCOMPARE(myText->contentHeight(), verticalFitHeight);
2157 myText->setElideMode(QQuickText::ElideMiddle);
2158 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2159 QVERIFY(myText->truncated());
2160 QVERIFY(myText->contentWidth() <= myText->width() + 2);
2161 QCOMPARE(myText->contentHeight(), verticalFitHeight);
2163 myText->setElideMode(QQuickText::ElideNone);
2164 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2166 myText->setFontSizeMode(QQuickText::Fit);
2167 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2168 // Should be the same as HorizontalFit with no wrapping.
2169 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2170 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2172 // Elide won't affect the size with Fit.
2173 myText->setElideMode(QQuickText::ElideRight);
2174 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2175 QVERIFY(!myText->truncated());
2176 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2177 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2179 myText->setElideMode(QQuickText::ElideLeft);
2180 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2181 QVERIFY(!myText->truncated());
2182 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2183 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2185 myText->setElideMode(QQuickText::ElideMiddle);
2186 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2187 QVERIFY(!myText->truncated());
2188 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2189 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2191 myText->setElideMode(QQuickText::ElideNone);
2192 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2194 myText->setFontSizeMode(QQuickText::FixedSize);
2195 myText->setWrapMode(QQuickText::Wrap);
2196 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2198 originalWidth = myText->contentWidth();
2199 originalHeight = myText->contentHeight();
2201 // The original text wrapped should exceed the height of the item.
2202 QVERIFY(originalWidth <= myText->width() + 2);
2203 QVERIFY(originalHeight > myText->height());
2205 myText->setFontSizeMode(QQuickText::HorizontalFit);
2206 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2207 // HorizontalFit should reduce the font size to minimize wrapping, which brings it back to the
2208 // same size as without text wrapping.
2209 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2210 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2212 // Elide won't affect the size with HorizontalFit.
2213 myText->setElideMode(QQuickText::ElideRight);
2214 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2215 QVERIFY(!myText->truncated());
2216 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2217 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2219 myText->setElideMode(QQuickText::ElideNone);
2220 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2222 myText->setFontSizeMode(QQuickText::VerticalFit);
2223 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2224 // VerticalFit should reduce the size to the wrapped text within the vertical height.
2225 verticalFitHeight = myText->contentHeight();
2226 qreal verticalFitWidth = myText->contentWidth();
2227 QVERIFY(myText->contentWidth() <= myText->width() + 2);
2228 QVERIFY(verticalFitHeight <= myText->height() + 2);
2229 QVERIFY(verticalFitHeight < originalHeight);
2231 // Elide won't affect the height or width of a wrapped text with VerticalFit.
2232 myText->setElideMode(QQuickText::ElideRight);
2233 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2234 QVERIFY(!myText->truncated());
2235 QCOMPARE(myText->contentWidth(), verticalFitWidth);
2236 QCOMPARE(myText->contentHeight(), verticalFitHeight);
2238 myText->setElideMode(QQuickText::ElideNone);
2239 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2241 myText->setFontSizeMode(QQuickText::Fit);
2242 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2243 // Should be the same as VerticalFit with wrapping.
2244 QCOMPARE(myText->contentWidth(), verticalFitWidth);
2245 QCOMPARE(myText->contentHeight(), verticalFitHeight);
2247 // Elide won't affect the size with Fit.
2248 myText->setElideMode(QQuickText::ElideRight);
2249 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2250 QVERIFY(!myText->truncated());
2251 QCOMPARE(myText->contentWidth(), verticalFitWidth);
2252 QCOMPARE(myText->contentHeight(), verticalFitHeight);
2254 myText->setElideMode(QQuickText::ElideNone);
2255 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2257 myText->setFontSizeMode(QQuickText::FixedSize);
2258 myText->setMaximumLineCount(2);
2259 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2261 // The original text wrapped should exceed the height of the item.
2262 QVERIFY(originalWidth <= myText->width() + 2);
2263 QVERIFY(originalHeight > myText->height());
2265 myText->setFontSizeMode(QQuickText::HorizontalFit);
2266 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2267 // HorizontalFit should reduce the font size to minimize wrapping, which brings it back to the
2268 // same size as without text wrapping.
2269 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2270 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2272 // Elide won't affect the size with HorizontalFit.
2273 myText->setElideMode(QQuickText::ElideRight);
2274 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2275 QVERIFY(!myText->truncated());
2276 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2277 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2279 myText->setElideMode(QQuickText::ElideNone);
2280 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2282 myText->setFontSizeMode(QQuickText::VerticalFit);
2283 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2284 // VerticalFit should reduce the size to the wrapped text within the vertical height.
2285 verticalFitHeight = myText->contentHeight();
2286 verticalFitWidth = myText->contentWidth();
2287 QVERIFY(myText->contentWidth() <= myText->width() + 2);
2288 QVERIFY(verticalFitHeight <= myText->height() + 2);
2289 QVERIFY(verticalFitHeight < originalHeight);
2291 // Elide won't affect the height or width of a wrapped text with VerticalFit.
2292 myText->setElideMode(QQuickText::ElideRight);
2293 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2294 QVERIFY(!myText->truncated());
2295 QCOMPARE(myText->contentWidth(), verticalFitWidth);
2296 QCOMPARE(myText->contentHeight(), verticalFitHeight);
2298 myText->setElideMode(QQuickText::ElideNone);
2299 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2301 myText->setFontSizeMode(QQuickText::Fit);
2302 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2303 // Should be the same as VerticalFit with wrapping.
2304 QCOMPARE(myText->contentWidth(), verticalFitWidth);
2305 QCOMPARE(myText->contentHeight(), verticalFitHeight);
2307 // Elide won't affect the size with Fit.
2308 myText->setElideMode(QQuickText::ElideRight);
2309 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2310 QVERIFY(!myText->truncated());
2311 QCOMPARE(myText->contentWidth(), verticalFitWidth);
2312 QCOMPARE(myText->contentHeight(), verticalFitHeight);
2314 myText->setElideMode(QQuickText::ElideNone);
2315 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2318 void tst_qquicktext::fontSizeModeMultiline_data()
2320 QTest::addColumn<QString>("text");
2321 QTest::newRow("plain") << "The quick red fox jumped\n over the lazy brown dog";
2322 QTest::newRow("styledtext") << "<b>The quick red fox jumped<br/> over the lazy brown dog</b>";
2325 void tst_qquicktext::fontSizeModeMultiline()
2327 QFETCH(QString, text);
2329 QScopedPointer<QQuickView> canvas(createView(testFile("fontSizeMode.qml")));
2332 QQuickText *myText = canvas->rootObject()->findChild<QQuickText*>("myText");
2333 QVERIFY(myText != 0);
2335 myText->setText(text);
2336 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2338 qreal originalWidth = myText->contentWidth();
2339 qreal originalHeight = myText->contentHeight();
2340 QCOMPARE(myText->lineCount(), 2);
2342 // The original text unwrapped should exceed the width and height of the item.
2343 QVERIFY(originalWidth > myText->width());
2344 QVERIFY(originalHeight > myText->height());
2346 QFont font = myText->font();
2347 font.setPixelSize(64);
2349 myText->setFont(font);
2350 myText->setFontSizeMode(QQuickText::HorizontalFit);
2351 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2352 // Font size reduced to fit within the width of the item.
2353 QCOMPARE(myText->lineCount(), 2);
2354 qreal horizontalFitWidth = myText->contentWidth();
2355 qreal horizontalFitHeight = myText->contentHeight();
2356 QVERIFY(horizontalFitWidth <= myText->width() + 2); // rounding
2357 QVERIFY(horizontalFitHeight > myText->height());
2359 // Right eliding will remove the last line
2360 myText->setElideMode(QQuickText::ElideRight);
2361 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2362 QVERIFY(myText->truncated());
2363 QCOMPARE(myText->lineCount(), 1);
2364 QVERIFY(myText->contentWidth() <= myText->width() + 2);
2365 QVERIFY(myText->contentHeight() <= myText->height() + 2);
2367 // Left or middle eliding wont have any effect.
2368 myText->setElideMode(QQuickText::ElideLeft);
2369 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2370 QVERIFY(!myText->truncated());
2371 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2372 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2374 myText->setElideMode(QQuickText::ElideMiddle);
2375 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2376 QVERIFY(!myText->truncated());
2377 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2378 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2380 myText->setElideMode(QQuickText::ElideNone);
2381 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2383 myText->setFontSizeMode(QQuickText::VerticalFit);
2384 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2385 // Font size reduced to fit within the height of the item.
2386 qreal verticalFitWidth = myText->contentWidth();
2387 qreal verticalFitHeight = myText->contentHeight();
2388 QVERIFY(verticalFitWidth <= myText->width() + 2);
2389 QVERIFY(verticalFitHeight <= myText->height() + 2);
2391 // Elide will have no effect.
2392 myText->setElideMode(QQuickText::ElideRight);
2393 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2394 QVERIFY(!myText->truncated());
2395 QVERIFY(myText->contentWidth() <= myText->width() + 2);
2396 QCOMPARE(myText->contentWidth(), verticalFitWidth);
2397 QCOMPARE(myText->contentHeight(), verticalFitHeight);
2399 myText->setElideMode(QQuickText::ElideLeft);
2400 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2401 QVERIFY(!myText->truncated());
2402 QCOMPARE(myText->contentWidth(), verticalFitWidth);
2403 QCOMPARE(myText->contentHeight(), verticalFitHeight);
2405 myText->setElideMode(QQuickText::ElideMiddle);
2406 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2407 QVERIFY(!myText->truncated());
2408 QCOMPARE(myText->contentWidth(), verticalFitWidth);
2409 QCOMPARE(myText->contentHeight(), verticalFitHeight);
2411 myText->setElideMode(QQuickText::ElideNone);
2412 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2414 myText->setFontSizeMode(QQuickText::Fit);
2415 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2416 // Should be the same as VerticalFit with no wrapping.
2417 QCOMPARE(myText->contentWidth(), verticalFitWidth);
2418 QCOMPARE(myText->contentHeight(), verticalFitHeight);
2420 // Elide won't affect the size with Fit.
2421 myText->setElideMode(QQuickText::ElideRight);
2422 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2423 QVERIFY(!myText->truncated());
2424 QCOMPARE(myText->contentWidth(), verticalFitWidth);
2425 QCOMPARE(myText->contentHeight(), verticalFitHeight);
2427 myText->setElideMode(QQuickText::ElideLeft);
2428 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2429 QVERIFY(!myText->truncated());
2430 QCOMPARE(myText->contentWidth(), verticalFitWidth);
2431 QCOMPARE(myText->contentHeight(), verticalFitHeight);
2433 myText->setElideMode(QQuickText::ElideMiddle);
2434 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2435 QVERIFY(!myText->truncated());
2436 QCOMPARE(myText->contentWidth(), verticalFitWidth);
2437 QCOMPARE(myText->contentHeight(), verticalFitHeight);
2439 myText->setElideMode(QQuickText::ElideNone);
2440 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2442 myText->setFontSizeMode(QQuickText::FixedSize);
2443 myText->setWrapMode(QQuickText::Wrap);
2444 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2446 originalWidth = myText->contentWidth();
2447 originalHeight = myText->contentHeight();
2449 // The original text wrapped should exceed the height of the item.
2450 QVERIFY(originalWidth <= myText->width() + 2);
2451 QVERIFY(originalHeight > myText->height());
2453 myText->setFontSizeMode(QQuickText::HorizontalFit);
2454 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2455 // HorizontalFit should reduce the font size to minimize wrapping, which brings it back to the
2456 // same size as without text wrapping.
2457 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2458 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2460 // Text will be elided vertically with HorizontalFit
2461 myText->setElideMode(QQuickText::ElideRight);
2462 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2463 QVERIFY(myText->truncated());
2464 QVERIFY(myText->contentWidth() <= myText->width() + 2);
2465 QVERIFY(myText->contentHeight() <= myText->height() + 2);
2467 myText->setElideMode(QQuickText::ElideNone);
2468 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2470 myText->setFontSizeMode(QQuickText::VerticalFit);
2471 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2472 // VerticalFit should reduce the size to the wrapped text within the vertical height.
2473 verticalFitHeight = myText->contentHeight();
2474 verticalFitWidth = myText->contentWidth();
2475 QVERIFY(myText->contentWidth() <= myText->width() + 2);
2476 QVERIFY(verticalFitHeight <= myText->height() + 2);
2477 QVERIFY(verticalFitHeight < originalHeight);
2479 // Elide won't affect the height or width of a wrapped text with VerticalFit.
2480 myText->setElideMode(QQuickText::ElideRight);
2481 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2482 QVERIFY(!myText->truncated());
2483 QCOMPARE(myText->contentWidth(), verticalFitWidth);
2484 QCOMPARE(myText->contentHeight(), verticalFitHeight);
2486 myText->setElideMode(QQuickText::ElideNone);
2487 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2489 myText->setFontSizeMode(QQuickText::Fit);
2490 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2491 // Should be the same as VerticalFit with wrapping.
2492 QCOMPARE(myText->contentWidth(), verticalFitWidth);
2493 QCOMPARE(myText->contentHeight(), verticalFitHeight);
2495 // Elide won't affect the size with Fit.
2496 myText->setElideMode(QQuickText::ElideRight);
2497 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2498 QVERIFY(!myText->truncated());
2499 QCOMPARE(myText->contentWidth(), verticalFitWidth);
2500 QCOMPARE(myText->contentHeight(), verticalFitHeight);
2502 myText->setElideMode(QQuickText::ElideNone);
2503 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2505 myText->setFontSizeMode(QQuickText::FixedSize);
2506 myText->setMaximumLineCount(2);
2507 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2509 // The original text wrapped should exceed the height of the item.
2510 QVERIFY(originalWidth <= myText->width() + 2);
2511 QVERIFY(originalHeight > myText->height());
2513 myText->setFontSizeMode(QQuickText::HorizontalFit);
2514 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2515 // HorizontalFit should reduce the font size to minimize wrapping, which brings it back to the
2516 // same size as without text wrapping.
2517 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2518 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2520 // Elide won't affect the size with HorizontalFit.
2521 myText->setElideMode(QQuickText::ElideRight);
2522 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2523 QVERIFY(myText->truncated());
2524 QVERIFY(myText->contentWidth() <= myText->width() + 2);
2525 QVERIFY(myText->contentHeight() <= myText->height() + 2);
2527 myText->setElideMode(QQuickText::ElideNone);
2528 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2530 myText->setFontSizeMode(QQuickText::VerticalFit);
2531 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2532 // VerticalFit should reduce the size to the wrapped text within the vertical height.
2533 verticalFitHeight = myText->contentHeight();
2534 verticalFitWidth = myText->contentWidth();
2535 QVERIFY(myText->contentWidth() <= myText->width() + 2);
2536 QVERIFY(verticalFitHeight <= myText->height() + 2);
2537 QVERIFY(verticalFitHeight < originalHeight);
2539 // Elide won't affect the height or width of a wrapped text with VerticalFit.
2540 myText->setElideMode(QQuickText::ElideRight);
2541 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2542 QVERIFY(!myText->truncated());
2543 QCOMPARE(myText->contentWidth(), verticalFitWidth);
2544 QCOMPARE(myText->contentHeight(), verticalFitHeight);
2546 myText->setElideMode(QQuickText::ElideNone);
2547 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2549 myText->setFontSizeMode(QQuickText::Fit);
2550 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2551 // Should be the same as VerticalFit with wrapping.
2552 QCOMPARE(myText->contentWidth(), verticalFitWidth);
2553 QCOMPARE(myText->contentHeight(), verticalFitHeight);
2555 // Elide won't affect the size with Fit.
2556 myText->setElideMode(QQuickText::ElideRight);
2557 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2558 QVERIFY(!myText->truncated());
2559 QCOMPARE(myText->contentWidth(), verticalFitWidth);
2560 QCOMPARE(myText->contentHeight(), verticalFitHeight);
2562 myText->setElideMode(QQuickText::ElideNone);
2563 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2566 void tst_qquicktext::multilengthStrings_data()
2568 QTest::addColumn<QString>("source");
2569 QTest::newRow("No Wrap") << testFile("multilengthStrings.qml");
2570 QTest::newRow("Wrap") << testFile("multilengthStringsWrapped.qml");
2573 void tst_qquicktext::multilengthStrings()
2575 QFETCH(QString, source);
2577 QScopedPointer<QQuickView> canvas(createView(source));
2580 QQuickText *myText = canvas->rootObject()->findChild<QQuickText*>("myText");
2581 QVERIFY(myText != 0);
2583 const QString longText = "the quick brown fox jumped over the lazy dog";
2584 const QString mediumText = "the brown fox jumped over the dog";
2585 const QString shortText = "fox jumped dog";
2587 myText->setText(longText);
2588 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2589 const qreal longWidth = myText->contentWidth();
2590 const qreal longHeight = myText->contentHeight();
2592 myText->setText(mediumText);
2593 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2594 const qreal mediumWidth = myText->contentWidth();
2595 const qreal mediumHeight = myText->contentHeight();
2597 myText->setText(shortText);
2598 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2599 const qreal shortWidth = myText->contentWidth();
2600 const qreal shortHeight = myText->contentHeight();
2602 myText->setElideMode(QQuickText::ElideRight);
2603 myText->setText(longText + QLatin1Char('\x9c') + mediumText + QLatin1Char('\x9c') + shortText);
2605 myText->setSize(QSizeF(longWidth, longHeight));
2606 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2608 QCOMPARE(myText->contentWidth(), longWidth);
2609 QCOMPARE(myText->contentHeight(), longHeight);
2610 QCOMPARE(myText->truncated(), false);
2612 myText->setSize(QSizeF(mediumWidth, mediumHeight));
2613 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2615 QCOMPARE(myText->contentWidth(), mediumWidth);
2616 QCOMPARE(myText->contentHeight(), mediumHeight);
2617 QCOMPARE(myText->truncated(), true);
2619 myText->setSize(QSizeF(shortWidth, shortHeight));
2620 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2622 QCOMPARE(myText->contentWidth(), shortWidth);
2623 QCOMPARE(myText->contentHeight(), shortHeight);
2624 QCOMPARE(myText->truncated(), true);
2627 void tst_qquicktext::fontFormatSizes_data()
2629 QTest::addColumn<QString>("text");
2630 QTest::addColumn<QString>("textWithTag");
2631 QTest::addColumn<bool>("fontIsBigger");
2633 QTest::newRow("fs1") << "Hello world!" << "Hello <font size=\"1\">world</font>!" << false;
2634 QTest::newRow("fs2") << "Hello world!" << "Hello <font size=\"2\">world</font>!" << false;
2635 QTest::newRow("fs3") << "Hello world!" << "Hello <font size=\"3\">world</font>!" << false;
2636 QTest::newRow("fs4") << "Hello world!" << "Hello <font size=\"4\">world</font>!" << true;
2637 QTest::newRow("fs5") << "Hello world!" << "Hello <font size=\"5\">world</font>!" << true;
2638 QTest::newRow("fs6") << "Hello world!" << "Hello <font size=\"6\">world</font>!" << true;
2639 QTest::newRow("fs7") << "Hello world!" << "Hello <font size=\"7\">world</font>!" << true;
2640 QTest::newRow("h1") << "This is<br/>a font<br/> size test." << "This is <h1>a font</h1> size test." << true;
2641 QTest::newRow("h2") << "This is<br/>a font<br/> size test." << "This is <h2>a font</h2> size test." << true;
2642 QTest::newRow("h3") << "This is<br/>a font<br/> size test." << "This is <h3>a font</h3> size test." << true;
2643 QTest::newRow("h4") << "This is<br/>a font<br/> size test." << "This is <h4>a font</h4> size test." << true;
2644 QTest::newRow("h5") << "This is<br/>a font<br/> size test." << "This is <h5>a font</h5> size test." << false;
2645 QTest::newRow("h6") << "This is<br/>a font<br/> size test." << "This is <h6>a font</h6> size test." << false;
2648 void tst_qquicktext::fontFormatSizes()
2650 QFETCH(QString, text);
2651 QFETCH(QString, textWithTag);
2652 QFETCH(bool, fontIsBigger);
2654 QQuickView *view = new QQuickView;
2656 view->setSource(testFileUrl("pointFontSizes.qml"));
2659 QQuickText *qtext = view->rootObject()->findChild<QQuickText*>("text");
2660 QQuickText *qtextWithTag = view->rootObject()->findChild<QQuickText*>("textWithTag");
2661 QVERIFY(qtext != 0);
2662 QVERIFY(qtextWithTag != 0);
2664 qtext->setText(text);
2665 qtextWithTag->setText(textWithTag);
2667 for (int size = 6; size < 100; size += 4) {
2668 view->rootObject()->setProperty("pointSize", size);
2670 QVERIFY(qtext->height() <= qtextWithTag->height());
2672 QVERIFY(qtext->height() >= qtextWithTag->height());
2677 view->setSource(testFileUrl("pixelFontSizes.qml"));
2678 QQuickText *qtext = view->rootObject()->findChild<QQuickText*>("text");
2679 QQuickText *qtextWithTag = view->rootObject()->findChild<QQuickText*>("textWithTag");
2680 QVERIFY(qtext != 0);
2681 QVERIFY(qtextWithTag != 0);
2683 qtext->setText(text);
2684 qtextWithTag->setText(textWithTag);
2686 for (int size = 6; size < 100; size += 4) {
2687 view->rootObject()->setProperty("pixelSize", size);
2689 QVERIFY(qtext->height() <= qtextWithTag->height());
2691 QVERIFY(qtext->height() >= qtextWithTag->height());
2697 typedef qreal (*ExpectedBaseline)(QQuickText *item);
2698 Q_DECLARE_METATYPE(ExpectedBaseline)
2700 static qreal expectedBaselineTop(QQuickText *item)
2702 QFontMetricsF fm(item->font());
2706 static qreal expectedBaselineBottom(QQuickText *item)
2708 QFontMetricsF fm(item->font());
2709 return item->height() - item->contentHeight() + fm.ascent();
2712 static qreal expectedBaselineCenter(QQuickText *item)
2714 QFontMetricsF fm(item->font());
2715 return ((item->height() - item->contentHeight()) / 2) + fm.ascent();
2718 static qreal expectedBaselineBold(QQuickText *item)
2720 QFont font = item->font();
2722 QFontMetricsF fm(font);
2726 static qreal expectedBaselineImage(QQuickText *item)
2728 QFontMetricsF fm(item->font());
2729 // The line is positioned so the bottom of the line is aligned with the bottom of the image,
2730 // or image height - line height and the baseline is line position + ascent. Because
2731 // QTextLine's height is rounded up this can give slightly different results to image height
2733 return 181 - qCeil(fm.height()) + fm.ascent();
2736 static qreal expectedBaselineCustom(QQuickText *item)
2738 QFontMetricsF fm(item->font());
2739 return 16 + fm.ascent();
2742 static qreal expectedBaselineScaled(QQuickText *item)
2744 QFont font = item->font();
2745 QTextLayout layout(item->text().replace(QLatin1Char('\n'), QChar::LineSeparator));
2747 layout.setFont(font);
2749 layout.beginLayout();
2750 for (QTextLine line = layout.createLine(); line.isValid(); line = layout.createLine()) {
2751 line.setLineWidth(FLT_MAX);
2752 width = qMax(line.naturalTextWidth(), width);
2756 if (width < item->width()) {
2757 QFontMetricsF fm(layout.font());
2760 font.setPointSize(font.pointSize() - 1);
2761 } while (font.pointSize() > 0);
2765 static qreal expectedBaselineFixedBottom(QQuickText *item)
2767 QFontMetricsF fm(item->font());
2768 qreal dy = item->text().contains(QLatin1Char('\n'))
2771 return dy + fm.ascent();
2774 static qreal expectedBaselineProportionalBottom(QQuickText *item)
2776 QFontMetricsF fm(item->font());
2777 qreal dy = item->text().contains(QLatin1Char('\n'))
2778 ? 200 - (qCeil(fm.height()) * 3)
2779 : 200 - (qCeil(fm.height()) * 1.5);
2780 return dy + fm.ascent();
2783 void tst_qquicktext::baselineOffset_data()
2785 qRegisterMetaType<ExpectedBaseline>();
2786 QTest::addColumn<QString>("text");
2787 QTest::addColumn<QString>("wrappedText");
2788 QTest::addColumn<QByteArray>("bindings");
2789 QTest::addColumn<ExpectedBaseline>("expectedBaseline");
2790 QTest::addColumn<ExpectedBaseline>("expectedBaselineEmpty");
2792 QTest::newRow("top align")
2795 << QByteArray("height: 200; verticalAlignment: Text.AlignTop")
2796 << &expectedBaselineTop
2797 << &expectedBaselineTop;
2798 QTest::newRow("bottom align")
2801 << QByteArray("height: 200; verticalAlignment: Text.AlignBottom")
2802 << &expectedBaselineBottom
2803 << &expectedBaselineBottom;
2804 QTest::newRow("center align")
2807 << QByteArray("height: 200; verticalAlignment: Text.AlignVCenter")
2808 << &expectedBaselineCenter
2809 << &expectedBaselineCenter;
2811 QTest::newRow("bold")
2812 << "<b>hello world</b>"
2813 << "<b>hello<br/>world</b>"
2814 << QByteArray("height: 200")
2815 << &expectedBaselineTop
2816 << &expectedBaselineBold;
2818 QTest::newRow("richText")
2819 << "<b>hello world</b>"
2820 << "<b>hello<br/>world</b>"
2821 << QByteArray("height: 200; textFormat: Text.RichText")
2822 << &expectedBaselineTop
2823 << &expectedBaselineTop;
2825 QTest::newRow("elided")
2828 << QByteArray("width: 20; height: 8; elide: Text.ElideRight")
2829 << &expectedBaselineTop
2830 << &expectedBaselineTop;
2832 QTest::newRow("elided bottom align")
2834 << "hello\nworld!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
2835 << QByteArray("width: 200; height: 200; elide: Text.ElideRight; verticalAlignment: Text.AlignBottom")
2836 << &expectedBaselineBottom
2837 << &expectedBaselineBottom;
2839 QTest::newRow("image")
2840 << "hello <img src=\"images/heart200.png\" /> world"
2841 << "hello <img src=\"images/heart200.png\" /><br/>world"
2842 << QByteArray("height: 200\n; baseUrl: \"") + testFileUrl("reference").toEncoded() + QByteArray("\"")
2843 << &expectedBaselineImage
2844 << &expectedBaselineTop;
2846 QTest::newRow("customLine")
2849 << QByteArray("height: 200; onLineLaidOut: line.y += 16")
2850 << &expectedBaselineCustom
2851 << &expectedBaselineCustom;
2853 QTest::newRow("scaled font")
2856 << QByteArray("width: 200; minimumPointSize: 1; font.pointSize: 64; fontSizeMode: Text.HorizontalFit")
2857 << &expectedBaselineScaled
2858 << &expectedBaselineTop;
2860 QTest::newRow("fixed line height top align")
2863 << QByteArray("height: 200; lineHeightMode: Text.FixedHeight; lineHeight: 20; verticalAlignment: Text.AlignTop")
2864 << &expectedBaselineTop
2865 << &expectedBaselineTop;
2867 QTest::newRow("fixed line height bottom align")
2870 << QByteArray("height: 200; lineHeightMode: Text.FixedHeight; lineHeight: 20; verticalAlignment: Text.AlignBottom")
2871 << &expectedBaselineFixedBottom
2872 << &expectedBaselineFixedBottom;
2874 QTest::newRow("proportional line height top align")
2877 << QByteArray("height: 200; lineHeightMode: Text.ProportionalHeight; lineHeight: 1.5; verticalAlignment: Text.AlignTop")
2878 << &expectedBaselineTop
2879 << &expectedBaselineTop;
2881 QTest::newRow("proportional line height bottom align")
2884 << QByteArray("height: 200; lineHeightMode: Text.ProportionalHeight; lineHeight: 1.5; verticalAlignment: Text.AlignBottom")
2885 << &expectedBaselineProportionalBottom
2886 << &expectedBaselineProportionalBottom;
2889 void tst_qquicktext::baselineOffset()
2891 QFETCH(QString, text);
2892 QFETCH(QString, wrappedText);
2893 QFETCH(QByteArray, bindings);
2894 QFETCH(ExpectedBaseline, expectedBaseline);
2895 QFETCH(ExpectedBaseline, expectedBaselineEmpty);
2897 QQmlComponent component(&engine);
2899 "import QtQuick 2.0\n"
2904 QScopedPointer<QObject> object(component.create());
2906 QQuickText *item = qobject_cast<QQuickText *>(object.data());
2910 qreal baseline = expectedBaselineEmpty(item);
2912 QCOMPARE(item->baselineOffset(), baseline);
2914 item->setText(text);
2915 if (expectedBaseline != expectedBaselineEmpty)
2916 baseline = expectedBaseline(item);
2918 QCOMPARE(item->baselineOffset(), baseline);
2920 item->setText(wrappedText);
2921 QCOMPARE(item->baselineOffset(), expectedBaseline(item));
2924 QFont font = item->font();
2925 font.setPointSize(font.pointSize() + 8);
2928 QCOMPARE(item->baselineOffset(), expectedBaseline(item));
2930 item->setText(text);
2931 qreal baseline = expectedBaseline(item);
2932 QCOMPARE(item->baselineOffset(), baseline);
2934 item->setText(QString());
2935 if (expectedBaselineEmpty != expectedBaseline)
2936 baseline = expectedBaselineEmpty(item);
2938 QCOMPARE(item->baselineOffset(), baseline);
2942 QTEST_MAIN(tst_qquicktext)
2944 #include "tst_qquicktext.moc"