1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the test suite of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include <QtTest/QSignalSpy>
43 #include <QTextDocument>
44 #include <QtQml/qqmlengine.h>
45 #include <QtQml/qqmlcomponent.h>
46 #include <QtQuick/private/qquicktext_p.h>
47 #include <private/qquicktext_p_p.h>
48 #include <private/qquickvaluetypes_p.h>
49 #include <QFontMetrics>
51 #include <QtQuick/QQuickView>
52 #include <private/qguiapplication_p.h>
54 #include <QtGui/QMouseEvent>
55 #include "../../shared/util.h"
56 #include "testhttpserver.h"
58 DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
60 #define SERVER_PORT 14459
61 #define SERVER_ADDR "http://127.0.0.1:14459"
63 Q_DECLARE_METATYPE(QQuickText::TextFormat)
66 extern void qt_setQtEnableTestFont(bool value);
69 class tst_qquicktext : public QQmlDataTest
80 void multilineElide_data();
81 void multilineElide();
82 void implicitElide_data();
86 void alignments_data();
90 void embeddedImages_data();
91 void embeddedImages();
96 // ### these tests may be trivial
97 void horizontalAlignment();
98 void horizontalAlignment_RightToLeft();
99 void verticalAlignment();
100 void hAlignImplicitWidth();
106 // QQuickFontValueType
111 void capitalization();
112 void letterSpacing();
115 void clickLink_data();
118 void implicitSize_data();
121 void implicitSizeBinding_data();
122 void implicitSizeBinding();
123 void geometryChanged();
125 void boundingRect_data();
129 void lineLaidOutRelayout();
131 void imgTagsBaseUrl_data();
132 void imgTagsBaseUrl();
133 void imgTagsAlign_data();
135 void imgTagsMultipleImages();
137 void imgTagsUpdates();
139 void fontSizeMode_data();
141 void fontSizeModeMultiline_data();
142 void fontSizeModeMultiline();
143 void multilengthStrings_data();
144 void multilengthStrings();
145 void fontFormatSizes_data();
146 void fontFormatSizes();
148 void baselineOffset_data();
149 void baselineOffset();
152 void htmlLists_data();
155 QStringList standard;
156 QStringList richText;
158 QStringList horizontalAlignmentmentStrings;
159 QStringList verticalAlignmentmentStrings;
161 QList<Qt::Alignment> verticalAlignmentments;
162 QList<Qt::Alignment> horizontalAlignmentments;
164 QStringList styleStrings;
165 QList<QQuickText::TextStyle> styles;
167 QStringList colorStrings;
171 QQuickView *createView(const QString &filename);
172 int numberOfNonWhitePixels(int fromX, int toX, const QImage &image);
175 tst_qquicktext::tst_qquicktext()
177 standard << "the quick brown fox jumped over the lazy dog"
178 << "the quick brown fox\n jumped over the lazy dog";
180 richText << "<i>the <b>quick</b> brown <a href=\\\"http://www.google.com\\\">fox</a> jumped over the <b>lazy</b> dog</i>"
181 << "<i>the <b>quick</b> brown <a href=\\\"http://www.google.com\\\">fox</a><br>jumped over the <b>lazy</b> dog</i>";
183 horizontalAlignmentmentStrings << "AlignLeft"
187 verticalAlignmentmentStrings << "AlignTop"
191 horizontalAlignmentments << Qt::AlignLeft
195 verticalAlignmentments << Qt::AlignTop
199 styleStrings << "Normal"
204 styles << QQuickText::Normal
205 << QQuickText::Outline
206 << QQuickText::Raised
207 << QQuickText::Sunken;
209 colorStrings << "aliceblue"
222 // need a different test to do alpha channel test
226 qt_setQtEnableTestFont(true);
229 QQuickView *tst_qquicktext::createView(const QString &filename)
231 QQuickView *canvas = new QQuickView(0);
233 canvas->setSource(QUrl::fromLocalFile(filename));
237 void tst_qquicktext::text()
240 QQmlComponent textComponent(&engine);
241 textComponent.setData("import QtQuick 2.0\nText { text: \"\" }", QUrl::fromLocalFile(""));
242 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
244 QVERIFY(textObject != 0);
245 QCOMPARE(textObject->text(), QString(""));
246 QVERIFY(textObject->width() == 0);
251 for (int i = 0; i < standard.size(); i++)
253 QString componentStr = "import QtQuick 2.0\nText { text: \"" + standard.at(i) + "\" }";
254 QQmlComponent textComponent(&engine);
255 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
257 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
259 QVERIFY(textObject != 0);
260 QCOMPARE(textObject->text(), standard.at(i));
261 QVERIFY(textObject->width() > 0);
266 for (int i = 0; i < richText.size(); i++)
268 QString componentStr = "import QtQuick 2.0\nText { text: \"" + richText.at(i) + "\" }";
269 QQmlComponent textComponent(&engine);
270 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
271 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
273 QVERIFY(textObject != 0);
274 QString expected = richText.at(i);
275 QCOMPARE(textObject->text(), expected.replace("\\\"", "\""));
276 QVERIFY(textObject->width() > 0);
282 void tst_qquicktext::width()
284 // uses Font metrics to find the width for standard and document to find the width for rich
286 QQmlComponent textComponent(&engine);
287 textComponent.setData("import QtQuick 2.0\nText { text: \"\" }", QUrl::fromLocalFile(""));
288 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
290 QVERIFY(textObject != 0);
291 QCOMPARE(textObject->width(), 0.);
296 bool requiresUnhintedMetrics = !qmlDisableDistanceField();
298 for (int i = 0; i < standard.size(); i++)
300 QVERIFY(!Qt::mightBeRichText(standard.at(i))); // self-test
303 qreal metricWidth = 0.0;
305 if (requiresUnhintedMetrics) {
306 QString s = standard.at(i);
307 s.replace(QLatin1Char('\n'), QChar::LineSeparator);
309 QTextLayout layout(s);
310 layout.setFlags(Qt::TextExpandTabs | Qt::TextShowMnemonic);
313 option.setUseDesignMetrics(true);
314 layout.setTextOption(option);
317 layout.beginLayout();
319 QTextLine line = layout.createLine();
326 metricWidth = layout.boundingRect().width();
329 metricWidth = fm.size(Qt::TextExpandTabs && Qt::TextShowMnemonic, standard.at(i)).width();
332 QString componentStr = "import QtQuick 2.0\nText { text: \"" + standard.at(i) + "\" }";
333 QQmlComponent textComponent(&engine);
334 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
335 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
337 QVERIFY(textObject != 0);
338 QVERIFY(textObject->boundingRect().width() > 0);
339 QCOMPARE(textObject->width(), qreal(metricWidth));
340 QVERIFY(textObject->textFormat() == QQuickText::AutoText); // setting text doesn't change format
345 for (int i = 0; i < richText.size(); i++)
347 QVERIFY(Qt::mightBeRichText(richText.at(i))); // self-test
349 QString componentStr = "import QtQuick 2.0\nText { text: \"" + richText.at(i) + "\"; textFormat: Text.RichText }";
350 QQmlComponent textComponent(&engine);
351 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
352 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
353 QVERIFY(textObject != 0);
355 QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject);
356 QVERIFY(textPrivate != 0);
357 QVERIFY(textPrivate->extra.isAllocated());
359 QTextDocument *doc = textPrivate->extra->doc;
362 QCOMPARE(int(textObject->width()), int(doc->idealWidth()));
363 QVERIFY(textObject->textFormat() == QQuickText::RichText);
369 void tst_qquicktext::wrap()
372 // for specified width and wrap set true
374 QQmlComponent textComponent(&engine);
375 textComponent.setData("import QtQuick 2.0\nText { text: \"Hello\"; wrapMode: Text.WordWrap; width: 300 }", QUrl::fromLocalFile(""));
376 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
377 textHeight = textObject->height();
379 QVERIFY(textObject != 0);
380 QVERIFY(textObject->wrapMode() == QQuickText::WordWrap);
381 QCOMPARE(textObject->width(), 300.);
386 for (int i = 0; i < standard.size(); i++)
388 QString componentStr = "import QtQuick 2.0\nText { wrapMode: Text.WordWrap; width: 30; text: \"" + standard.at(i) + "\" }";
389 QQmlComponent textComponent(&engine);
390 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
391 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
393 QVERIFY(textObject != 0);
394 QCOMPARE(textObject->width(), 30.);
395 QVERIFY(textObject->height() > textHeight);
397 int oldHeight = textObject->height();
398 textObject->setWidth(100);
399 QVERIFY(textObject->height() < oldHeight);
404 for (int i = 0; i < richText.size(); i++)
406 QString componentStr = "import QtQuick 2.0\nText { wrapMode: Text.WordWrap; width: 30; text: \"" + richText.at(i) + "\" }";
407 QQmlComponent textComponent(&engine);
408 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
409 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
411 QVERIFY(textObject != 0);
412 QCOMPARE(textObject->width(), 30.);
413 QVERIFY(textObject->height() > textHeight);
415 qreal oldHeight = textObject->height();
416 textObject->setWidth(100);
417 QVERIFY(textObject->height() < oldHeight);
422 // richtext again with a fixed height
423 for (int i = 0; i < richText.size(); i++)
425 QString componentStr = "import QtQuick 2.0\nText { wrapMode: Text.WordWrap; width: 30; height: 50; text: \"" + richText.at(i) + "\" }";
426 QQmlComponent textComponent(&engine);
427 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
428 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
430 QVERIFY(textObject != 0);
431 QCOMPARE(textObject->width(), 30.);
432 QVERIFY(textObject->implicitHeight() > textHeight);
434 qreal oldHeight = textObject->implicitHeight();
435 textObject->setWidth(100);
436 QVERIFY(textObject->implicitHeight() < oldHeight);
442 void tst_qquicktext::elide()
444 for (QQuickText::TextElideMode m = QQuickText::ElideLeft; m<=QQuickText::ElideNone; m=QQuickText::TextElideMode(int(m)+1)) {
445 const char* elidename[]={"ElideLeft", "ElideRight", "ElideMiddle", "ElideNone"};
446 QString elide = "elide: Text." + QString(elidename[int(m)]) + ";";
448 // XXX Poor coverage.
451 QQmlComponent textComponent(&engine);
452 textComponent.setData(("import QtQuick 2.0\nText { text: \"\"; "+elide+" width: 100 }").toLatin1(), QUrl::fromLocalFile(""));
453 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
455 QCOMPARE(textObject->elideMode(), m);
456 QCOMPARE(textObject->width(), 100.);
461 for (int i = 0; i < standard.size(); i++)
463 QString componentStr = "import QtQuick 2.0\nText { "+elide+" width: 100; text: \"" + standard.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('\n'))
472 QVERIFY(textObject->contentWidth() <= textObject->width());
477 for (int i = 0; i < richText.size(); i++)
479 QString componentStr = "import QtQuick 2.0\nText { "+elide+" width: 100; text: \"" + richText.at(i) + "\" }";
480 QQmlComponent textComponent(&engine);
481 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
482 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
484 QCOMPARE(textObject->elideMode(), m);
485 QCOMPARE(textObject->width(), 100.);
487 if (m != QQuickText::ElideNone && standard.at(i).contains("<br>"))
488 QVERIFY(textObject->contentWidth() <= textObject->width());
495 void tst_qquicktext::multilineElide_data()
497 QTest::addColumn<QQuickText::TextFormat>("format");
498 QTest::newRow("plain") << QQuickText::PlainText;
499 QTest::newRow("styled") << QQuickText::StyledText;
502 void tst_qquicktext::multilineElide()
504 QFETCH(QQuickText::TextFormat, format);
505 QQuickView *canvas = createView(testFile("multilineelide.qml"));
507 QQuickText *myText = qobject_cast<QQuickText*>(canvas->rootObject());
508 QVERIFY(myText != 0);
509 myText->setTextFormat(format);
511 QCOMPARE(myText->lineCount(), 3);
512 QCOMPARE(myText->truncated(), true);
514 qreal lineHeight = myText->contentHeight() / 3.;
516 // Set a valid height greater than the truncated content height and ensure the line count is
518 myText->setHeight(200);
519 QCOMPARE(myText->lineCount(), 3);
520 QCOMPARE(myText->truncated(), true);
522 // reduce size and ensure fewer lines are drawn
523 myText->setHeight(lineHeight * 2);
524 QCOMPARE(myText->lineCount(), 2);
526 myText->setHeight(lineHeight);
527 QCOMPARE(myText->lineCount(), 1);
529 myText->setHeight(5);
530 QCOMPARE(myText->lineCount(), 1);
532 myText->setHeight(lineHeight * 3);
533 QCOMPARE(myText->lineCount(), 3);
535 // remove max count and show all lines.
536 myText->setHeight(1000);
537 myText->resetMaximumLineCount();
539 QCOMPARE(myText->truncated(), false);
542 myText->setHeight(lineHeight * 2);
543 QCOMPARE(myText->lineCount(), 2);
544 QCOMPARE(myText->truncated(), true);
546 // change line height
547 myText->setLineHeight(1.1);
548 QCOMPARE(myText->lineCount(), 1);
553 void tst_qquicktext::implicitElide_data()
555 QTest::addColumn<QString>("width");
556 QTest::addColumn<QString>("initialText");
557 QTest::addColumn<QString>("text");
559 QTest::newRow("maximum width, empty")
560 << "Math.min(implicitWidth, 100)"
562 QTest::newRow("maximum width, short")
563 << "Math.min(implicitWidth, 100)"
565 QTest::newRow("maximum width, long")
566 << "Math.min(implicitWidth, 100)"
567 << "the quick brown fox jumped over the lazy dog";
568 QTest::newRow("reset width, empty")
569 << "implicitWidth > 100 ? 100 : undefined"
571 QTest::newRow("reset width, short")
572 << "implicitWidth > 100 ? 100 : undefined"
574 QTest::newRow("reset width, long")
575 << "implicitWidth > 100 ? 100 : undefined"
576 << "the quick brown fox jumped over the lazy dog";
579 void tst_qquicktext::implicitElide()
581 QFETCH(QString, width);
582 QFETCH(QString, initialText);
584 QString componentStr =
585 "import QtQuick 2.0\n"
587 "width: " + width + "\n"
588 "text: \"" + initialText + "\"\n"
589 "elide: Text.ElideRight\n"
591 QQmlComponent textComponent(&engine);
592 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
593 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
595 QVERIFY(textObject->contentWidth() <= textObject->width());
597 textObject->setText("the quick brown fox jumped over");
599 QVERIFY(textObject->contentWidth() > 0);
600 QVERIFY(textObject->contentWidth() <= textObject->width());
603 void tst_qquicktext::textFormat()
606 QQmlComponent textComponent(&engine);
607 textComponent.setData("import QtQuick 2.0\nText { text: \"Hello\"; textFormat: Text.RichText }", QUrl::fromLocalFile(""));
608 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
610 QVERIFY(textObject != 0);
611 QVERIFY(textObject->textFormat() == QQuickText::RichText);
613 QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject);
614 QVERIFY(textPrivate != 0);
615 QVERIFY(textPrivate->richText == true);
620 QQmlComponent textComponent(&engine);
621 textComponent.setData("import QtQuick 2.0\nText { text: \"<b>Hello</b>\" }", QUrl::fromLocalFile(""));
622 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
624 QVERIFY(textObject != 0);
625 QVERIFY(textObject->textFormat() == QQuickText::AutoText);
627 QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject);
628 QVERIFY(textPrivate != 0);
629 QVERIFY(textPrivate->styledText == true);
634 QQmlComponent textComponent(&engine);
635 textComponent.setData("import QtQuick 2.0\nText { text: \"<b>Hello</b>\"; textFormat: Text.PlainText }", QUrl::fromLocalFile(""));
636 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
638 QVERIFY(textObject != 0);
639 QVERIFY(textObject->textFormat() == QQuickText::PlainText);
646 void tst_qquicktext::alignments_data()
648 QTest::addColumn<int>("hAlign");
649 QTest::addColumn<int>("vAlign");
650 QTest::addColumn<QString>("expectfile");
652 QTest::newRow("LT") << int(Qt::AlignLeft) << int(Qt::AlignTop) << testFile("alignments_lt.png");
653 QTest::newRow("RT") << int(Qt::AlignRight) << int(Qt::AlignTop) << testFile("alignments_rt.png");
654 QTest::newRow("CT") << int(Qt::AlignHCenter) << int(Qt::AlignTop) << testFile("alignments_ct.png");
656 QTest::newRow("LB") << int(Qt::AlignLeft) << int(Qt::AlignBottom) << testFile("alignments_lb.png");
657 QTest::newRow("RB") << int(Qt::AlignRight) << int(Qt::AlignBottom) << testFile("alignments_rb.png");
658 QTest::newRow("CB") << int(Qt::AlignHCenter) << int(Qt::AlignBottom) << testFile("alignments_cb.png");
660 QTest::newRow("LC") << int(Qt::AlignLeft) << int(Qt::AlignVCenter) << testFile("alignments_lc.png");
661 QTest::newRow("RC") << int(Qt::AlignRight) << int(Qt::AlignVCenter) << testFile("alignments_rc.png");
662 QTest::newRow("CC") << int(Qt::AlignHCenter) << int(Qt::AlignVCenter) << testFile("alignments_cc.png");
666 void tst_qquicktext::alignments()
668 QSKIP("Text alignment pixmap comparison tests will not work with scenegraph");
669 #if (0)// No widgets in scenegraph
672 QFETCH(QString, expectfile);
674 QQuickView *canvas = createView(testFile("alignments.qml"));
676 canvas->requestActivateWindow();
678 QTRY_COMPARE(QGuiApplication::activeWindow(), static_cast<QWidget *>(canvas));
680 QObject *ob = canvas->rootObject();
682 ob->setProperty("horizontalAlignment",hAlign);
683 ob->setProperty("verticalAlignment",vAlign);
684 QTRY_COMPARE(ob->property("running").toBool(),false);
685 QImage actual(canvas->width(), canvas->height(), QImage::Format_RGB32);
686 actual.fill(qRgb(255,255,255));
690 QImage expect(expectfile);
691 if (QGuiApplicationPrivate::graphics_system_name == "raster" || QGuiApplicationPrivate::graphics_system_name == "") {
692 QCOMPARE(actual,expect);
698 //the alignment tests may be trivial o.oa
699 void tst_qquicktext::horizontalAlignment()
701 //test one align each, and then test if two align fails.
703 for (int i = 0; i < standard.size(); i++)
705 for (int j=0; j < horizontalAlignmentmentStrings.size(); j++)
707 QString componentStr = "import QtQuick 2.0\nText { horizontalAlignment: \"" + horizontalAlignmentmentStrings.at(j) + "\"; text: \"" + standard.at(i) + "\" }";
708 QQmlComponent textComponent(&engine);
709 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
710 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
712 QCOMPARE((int)textObject->hAlign(), (int)horizontalAlignmentments.at(j));
718 for (int i = 0; i < richText.size(); i++)
720 for (int j=0; j < horizontalAlignmentmentStrings.size(); j++)
722 QString componentStr = "import QtQuick 2.0\nText { horizontalAlignment: \"" + horizontalAlignmentmentStrings.at(j) + "\"; text: \"" + richText.at(i) + "\" }";
723 QQmlComponent textComponent(&engine);
724 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
725 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
727 QCOMPARE((int)textObject->hAlign(), (int)horizontalAlignmentments.at(j));
735 void tst_qquicktext::horizontalAlignment_RightToLeft()
737 QQuickView *canvas = createView(testFile("horizontalAlignment_RightToLeft.qml"));
738 QQuickText *text = canvas->rootObject()->findChild<QQuickText*>("text");
742 QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(text);
743 QVERIFY(textPrivate != 0);
745 QTRY_VERIFY(textPrivate->layout.lineCount());
747 // implicit alignment should follow the reading direction of RTL text
748 QCOMPARE(text->hAlign(), QQuickText::AlignRight);
749 QCOMPARE(text->effectiveHAlign(), text->hAlign());
750 QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > canvas->width()/2);
752 // explicitly left aligned text
753 text->setHAlign(QQuickText::AlignLeft);
754 QCOMPARE(text->hAlign(), QQuickText::AlignLeft);
755 QCOMPARE(text->effectiveHAlign(), text->hAlign());
756 QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() < canvas->width()/2);
758 // explicitly right aligned text
759 text->setHAlign(QQuickText::AlignRight);
760 QCOMPARE(text->hAlign(), QQuickText::AlignRight);
761 QCOMPARE(text->effectiveHAlign(), text->hAlign());
762 QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > canvas->width()/2);
764 // change to rich text
765 QString textString = text->text();
766 text->setText(QString("<i>") + textString + QString("</i>"));
767 text->setTextFormat(QQuickText::RichText);
770 // implicitly aligned rich text should follow the reading direction of text
771 QCOMPARE(text->hAlign(), QQuickText::AlignRight);
772 QCOMPARE(text->effectiveHAlign(), text->hAlign());
773 QVERIFY(textPrivate->extra.isAllocated());
774 QVERIFY(textPrivate->extra->doc->defaultTextOption().alignment() & Qt::AlignLeft);
776 // explicitly left aligned rich text
777 text->setHAlign(QQuickText::AlignLeft);
778 QCOMPARE(text->hAlign(), QQuickText::AlignLeft);
779 QCOMPARE(text->effectiveHAlign(), text->hAlign());
780 QVERIFY(textPrivate->extra->doc->defaultTextOption().alignment() & Qt::AlignRight);
782 // explicitly right aligned rich text
783 text->setHAlign(QQuickText::AlignRight);
784 QCOMPARE(text->hAlign(), QQuickText::AlignRight);
785 QCOMPARE(text->effectiveHAlign(), text->hAlign());
786 QVERIFY(textPrivate->extra->doc->defaultTextOption().alignment() & Qt::AlignLeft);
788 text->setText(textString);
789 text->setTextFormat(QQuickText::PlainText);
791 // explicitly center aligned
792 text->setHAlign(QQuickText::AlignHCenter);
793 QCOMPARE(text->hAlign(), QQuickText::AlignHCenter);
794 QCOMPARE(text->effectiveHAlign(), text->hAlign());
795 QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() < canvas->width()/2);
796 QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().right() > canvas->width()/2);
798 // reseted alignment should go back to following the text reading direction
800 QCOMPARE(text->hAlign(), QQuickText::AlignRight);
801 QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > canvas->width()/2);
803 // mirror the text item
804 QQuickItemPrivate::get(text)->setLayoutMirror(true);
806 // mirrored implicit alignment should continue to follow the reading direction of the text
807 QCOMPARE(text->hAlign(), QQuickText::AlignRight);
808 QCOMPARE(text->effectiveHAlign(), QQuickText::AlignRight);
809 QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > canvas->width()/2);
811 // mirrored explicitly right aligned behaves as left aligned
812 text->setHAlign(QQuickText::AlignRight);
813 QCOMPARE(text->hAlign(), QQuickText::AlignRight);
814 QCOMPARE(text->effectiveHAlign(), QQuickText::AlignLeft);
815 QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() < canvas->width()/2);
817 // mirrored explicitly left aligned behaves as right aligned
818 text->setHAlign(QQuickText::AlignLeft);
819 QCOMPARE(text->hAlign(), QQuickText::AlignLeft);
820 QCOMPARE(text->effectiveHAlign(), QQuickText::AlignRight);
821 QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > canvas->width()/2);
824 QQuickItemPrivate::get(text)->setLayoutMirror(false);
827 // English text should be implicitly left aligned
828 text->setText("Hello world!");
829 QCOMPARE(text->hAlign(), QQuickText::AlignLeft);
830 QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() < canvas->width()/2);
832 // empty text with implicit alignment follows the system locale-based
833 // keyboard input direction from QInputMethod::inputDirection()
835 QCOMPARE(text->hAlign(), qApp->inputMethod()->inputDirection() == Qt::LeftToRight ?
836 QQuickText::AlignLeft : QQuickText::AlignRight);
837 text->setHAlign(QQuickText::AlignRight);
838 QCOMPARE(text->hAlign(), QQuickText::AlignRight);
842 // alignment of Text with no text set to it
843 QString componentStr = "import QtQuick 2.0\nText {}";
844 QQmlComponent textComponent(&engine);
845 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
846 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
847 QCOMPARE(textObject->hAlign(), qApp->inputMethod()->inputDirection() == Qt::LeftToRight ?
848 QQuickText::AlignLeft : QQuickText::AlignRight);
852 int tst_qquicktext::numberOfNonWhitePixels(int fromX, int toX, const QImage &image)
855 for (int x = fromX; x < toX; ++x) {
856 for (int y = 0; y < image.height(); ++y) {
857 if (image.pixel(x, y) != qRgb(255, 255, 255))
864 void tst_qquicktext::hAlignImplicitWidth()
866 QQuickView view(testFileUrl("hAlignImplicitWidth.qml"));
868 view.requestActivateWindow();
869 QTest::qWaitForWindowShown(&view);
871 QQuickText *text = view.rootObject()->findChild<QQuickText*>("textItem");
876 QImage image = view.grabFrameBuffer();
877 int left = numberOfNonWhitePixels(0, image.width() / 3, image);
878 int mid = numberOfNonWhitePixels(image.width() / 3, 2 * image.width() / 3, image);
879 int right = numberOfNonWhitePixels( 2 * image.width() / 3, image.width(), image);
881 QVERIFY(mid > right);
885 text->setHAlign(QQuickText::AlignHCenter);
886 QImage image = view.grabFrameBuffer();
887 int left = numberOfNonWhitePixels(0, image.width() / 3, image);
888 int mid = numberOfNonWhitePixels(image.width() / 3, 2 * image.width() / 3, image);
889 int right = numberOfNonWhitePixels( 2 * image.width() / 3, image.width(), image);
891 QVERIFY(mid > right);
895 text->setHAlign(QQuickText::AlignRight);
896 QImage image = view.grabFrameBuffer();
897 int left = numberOfNonWhitePixels(0, image.width() / 3, image);
898 int mid = numberOfNonWhitePixels(image.width() / 3, 2 * image.width() / 3, image);
899 int right = numberOfNonWhitePixels( 2 * image.width() / 3, image.width(), image);
901 QVERIFY(mid < right);
905 void tst_qquicktext::verticalAlignment()
907 //test one align each, and then test if two align fails.
909 for (int i = 0; i < standard.size(); i++)
911 for (int j=0; j < verticalAlignmentmentStrings.size(); j++)
913 QString componentStr = "import QtQuick 2.0\nText { verticalAlignment: \"" + verticalAlignmentmentStrings.at(j) + "\"; text: \"" + standard.at(i) + "\" }";
914 QQmlComponent textComponent(&engine);
915 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
916 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
918 QVERIFY(textObject != 0);
919 QCOMPARE((int)textObject->vAlign(), (int)verticalAlignmentments.at(j));
925 for (int i = 0; i < richText.size(); i++)
927 for (int j=0; j < verticalAlignmentmentStrings.size(); j++)
929 QString componentStr = "import QtQuick 2.0\nText { verticalAlignment: \"" + verticalAlignmentmentStrings.at(j) + "\"; text: \"" + richText.at(i) + "\" }";
930 QQmlComponent textComponent(&engine);
931 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
932 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
934 QVERIFY(textObject != 0);
935 QCOMPARE((int)textObject->vAlign(), (int)verticalAlignmentments.at(j));
943 void tst_qquicktext::font()
945 //test size, then bold, then italic, then family
947 QString componentStr = "import QtQuick 2.0\nText { font.pointSize: 40; text: \"Hello World\" }";
948 QQmlComponent textComponent(&engine);
949 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
950 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
952 QCOMPARE(textObject->font().pointSize(), 40);
953 QCOMPARE(textObject->font().bold(), false);
954 QCOMPARE(textObject->font().italic(), false);
960 QString componentStr = "import QtQuick 2.0\nText { font.pixelSize: 40; text: \"Hello World\" }";
961 QQmlComponent textComponent(&engine);
962 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
963 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
965 QCOMPARE(textObject->font().pixelSize(), 40);
966 QCOMPARE(textObject->font().bold(), false);
967 QCOMPARE(textObject->font().italic(), false);
973 QString componentStr = "import QtQuick 2.0\nText { font.bold: true; text: \"Hello World\" }";
974 QQmlComponent textComponent(&engine);
975 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
976 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
978 QCOMPARE(textObject->font().bold(), true);
979 QCOMPARE(textObject->font().italic(), false);
985 QString componentStr = "import QtQuick 2.0\nText { font.italic: true; text: \"Hello World\" }";
986 QQmlComponent textComponent(&engine);
987 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
988 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
990 QCOMPARE(textObject->font().italic(), true);
991 QCOMPARE(textObject->font().bold(), false);
997 QString componentStr = "import QtQuick 2.0\nText { font.family: \"Helvetica\"; text: \"Hello World\" }";
998 QQmlComponent textComponent(&engine);
999 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1000 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1002 QCOMPARE(textObject->font().family(), QString("Helvetica"));
1003 QCOMPARE(textObject->font().bold(), false);
1004 QCOMPARE(textObject->font().italic(), false);
1010 QString componentStr = "import QtQuick 2.0\nText { font.family: \"\"; text: \"Hello World\" }";
1011 QQmlComponent textComponent(&engine);
1012 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1013 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1015 QCOMPARE(textObject->font().family(), QString(""));
1021 void tst_qquicktext::style()
1024 for (int i = 0; i < styles.size(); i++)
1026 QString componentStr = "import QtQuick 2.0\nText { style: \"" + styleStrings.at(i) + "\"; styleColor: \"white\"; text: \"Hello World\" }";
1027 QQmlComponent textComponent(&engine);
1028 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1029 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1031 QCOMPARE((int)textObject->style(), (int)styles.at(i));
1032 QCOMPARE(textObject->styleColor(), QColor("white"));
1036 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello World\" }";
1037 QQmlComponent textComponent(&engine);
1038 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1039 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1041 QRectF brPre = textObject->boundingRect();
1042 textObject->setStyle(QQuickText::Outline);
1043 QRectF brPost = textObject->boundingRect();
1045 QVERIFY(brPre.width() < brPost.width());
1046 QVERIFY(brPre.height() < brPost.height());
1051 void tst_qquicktext::color()
1054 for (int i = 0; i < colorStrings.size(); i++)
1056 QString componentStr = "import QtQuick 2.0\nText { color: \"" + colorStrings.at(i) + "\"; text: \"Hello World\" }";
1057 QQmlComponent textComponent(&engine);
1058 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1059 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1061 QCOMPARE(textObject->color(), QColor(colorStrings.at(i)));
1062 QCOMPARE(textObject->styleColor(), QColor("black"));
1063 QCOMPARE(textObject->linkColor(), QColor("blue"));
1068 for (int i = 0; i < colorStrings.size(); i++)
1070 QString componentStr = "import QtQuick 2.0\nText { styleColor: \"" + colorStrings.at(i) + "\"; text: \"Hello World\" }";
1071 QQmlComponent textComponent(&engine);
1072 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1073 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1075 QCOMPARE(textObject->styleColor(), QColor(colorStrings.at(i)));
1076 // default color to black?
1077 QCOMPARE(textObject->color(), QColor("black"));
1078 QCOMPARE(textObject->linkColor(), QColor("blue"));
1083 for (int i = 0; i < colorStrings.size(); i++)
1085 QString componentStr = "import QtQuick 2.0\nText { linkColor: \"" + colorStrings.at(i) + "\"; text: \"Hello World\" }";
1086 QQmlComponent textComponent(&engine);
1087 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1088 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1090 QCOMPARE(textObject->styleColor(), QColor("black"));
1091 QCOMPARE(textObject->color(), QColor("black"));
1092 QCOMPARE(textObject->linkColor(), QColor(colorStrings.at(i)));
1097 for (int i = 0; i < colorStrings.size(); i++)
1099 for (int j = 0; j < colorStrings.size(); j++)
1101 QString componentStr = "import QtQuick 2.0\nText { "
1102 "color: \"" + colorStrings.at(i) + "\"; "
1103 "styleColor: \"" + colorStrings.at(j) + "\"; "
1104 "linkColor: \"" + colorStrings.at(j) + "\"; "
1105 "text: \"Hello World\" }";
1106 QQmlComponent textComponent(&engine);
1107 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1108 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1110 QCOMPARE(textObject->color(), QColor(colorStrings.at(i)));
1111 QCOMPARE(textObject->styleColor(), QColor(colorStrings.at(j)));
1112 QCOMPARE(textObject->linkColor(), QColor(colorStrings.at(j)));
1118 QString colorStr = "#AA001234";
1119 QColor testColor("#001234");
1120 testColor.setAlpha(170);
1122 QString componentStr = "import QtQuick 2.0\nText { color: \"" + colorStr + "\"; text: \"Hello World\" }";
1123 QQmlComponent textComponent(&engine);
1124 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1125 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1127 QCOMPARE(textObject->color(), testColor);
1131 QString colorStr = "#001234";
1132 QColor testColor(colorStr);
1134 QString componentStr = "import QtQuick 2.0\nText { color: \"" + colorStr + "\"; text: \"Hello World\" }";
1135 QQmlComponent textComponent(&engine);
1136 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1137 QScopedPointer<QObject> object(textComponent.create());
1138 QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
1140 QSignalSpy spy(textObject, SIGNAL(colorChanged()));
1142 QCOMPARE(textObject->color(), testColor);
1143 textObject->setColor(testColor);
1144 QCOMPARE(textObject->color(), testColor);
1145 QCOMPARE(spy.count(), 0);
1147 testColor = QColor("black");
1148 textObject->setColor(testColor);
1149 QCOMPARE(textObject->color(), testColor);
1150 QCOMPARE(spy.count(), 1);
1152 QString colorStr = "#001234";
1153 QColor testColor(colorStr);
1155 QString componentStr = "import QtQuick 2.0\nText { styleColor: \"" + colorStr + "\"; text: \"Hello World\" }";
1156 QQmlComponent textComponent(&engine);
1157 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1158 QScopedPointer<QObject> object(textComponent.create());
1159 QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
1161 QSignalSpy spy(textObject, SIGNAL(styleColorChanged()));
1163 QCOMPARE(textObject->styleColor(), testColor);
1164 textObject->setStyleColor(testColor);
1165 QCOMPARE(textObject->styleColor(), testColor);
1166 QCOMPARE(spy.count(), 0);
1168 testColor = QColor("black");
1169 textObject->setStyleColor(testColor);
1170 QCOMPARE(textObject->styleColor(), testColor);
1171 QCOMPARE(spy.count(), 1);
1173 QString colorStr = "#001234";
1174 QColor testColor(colorStr);
1176 QString componentStr = "import QtQuick 2.0\nText { linkColor: \"" + colorStr + "\"; text: \"Hello World\" }";
1177 QQmlComponent textComponent(&engine);
1178 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1179 QScopedPointer<QObject> object(textComponent.create());
1180 QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
1182 QSignalSpy spy(textObject, SIGNAL(linkColorChanged()));
1184 QCOMPARE(textObject->linkColor(), testColor);
1185 textObject->setLinkColor(testColor);
1186 QCOMPARE(textObject->linkColor(), testColor);
1187 QCOMPARE(spy.count(), 0);
1189 testColor = QColor("black");
1190 textObject->setLinkColor(testColor);
1191 QCOMPARE(textObject->linkColor(), testColor);
1192 QCOMPARE(spy.count(), 1);
1196 void tst_qquicktext::smooth()
1198 for (int i = 0; i < standard.size(); i++)
1201 QString componentStr = "import QtQuick 2.0\nText { smooth: false; text: \"" + standard.at(i) + "\" }";
1202 QQmlComponent textComponent(&engine);
1203 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1204 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1205 QCOMPARE(textObject->smooth(), false);
1210 QString componentStr = "import QtQuick 2.0\nText { text: \"" + standard.at(i) + "\" }";
1211 QQmlComponent textComponent(&engine);
1212 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1213 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1214 QCOMPARE(textObject->smooth(), true);
1219 for (int i = 0; i < richText.size(); i++)
1222 QString componentStr = "import QtQuick 2.0\nText { smooth: false; text: \"" + richText.at(i) + "\" }";
1223 QQmlComponent textComponent(&engine);
1224 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1225 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1226 QCOMPARE(textObject->smooth(), false);
1231 QString componentStr = "import QtQuick 2.0\nText { text: \"" + richText.at(i) + "\" }";
1232 QQmlComponent textComponent(&engine);
1233 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1234 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1235 QCOMPARE(textObject->smooth(), true);
1242 void tst_qquicktext::weight()
1245 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
1246 QQmlComponent textComponent(&engine);
1247 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1248 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1250 QVERIFY(textObject != 0);
1251 QCOMPARE((int)textObject->font().weight(), (int)QQuickFontValueType::Normal);
1256 QString componentStr = "import QtQuick 2.0\nText { font.weight: \"Bold\"; text: \"Hello world!\" }";
1257 QQmlComponent textComponent(&engine);
1258 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1259 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1261 QVERIFY(textObject != 0);
1262 QCOMPARE((int)textObject->font().weight(), (int)QQuickFontValueType::Bold);
1268 void tst_qquicktext::underline()
1270 QQuickView view(testFileUrl("underline.qml"));
1272 view.requestActivateWindow();
1273 QTest::qWaitForWindowShown(&view);
1274 QQuickText *textObject = view.rootObject()->findChild<QQuickText*>("myText");
1275 QVERIFY(textObject != 0);
1276 QCOMPARE(textObject->font().overline(), false);
1277 QCOMPARE(textObject->font().underline(), true);
1278 QCOMPARE(textObject->font().strikeOut(), false);
1281 void tst_qquicktext::overline()
1283 QQuickView view(testFileUrl("overline.qml"));
1285 view.requestActivateWindow();
1286 QTest::qWaitForWindowShown(&view);
1287 QQuickText *textObject = view.rootObject()->findChild<QQuickText*>("myText");
1288 QVERIFY(textObject != 0);
1289 QCOMPARE(textObject->font().overline(), true);
1290 QCOMPARE(textObject->font().underline(), false);
1291 QCOMPARE(textObject->font().strikeOut(), false);
1294 void tst_qquicktext::strikeout()
1296 QQuickView view(testFileUrl("strikeout.qml"));
1298 view.requestActivateWindow();
1299 QTest::qWaitForWindowShown(&view);
1300 QQuickText *textObject = view.rootObject()->findChild<QQuickText*>("myText");
1301 QVERIFY(textObject != 0);
1302 QCOMPARE(textObject->font().overline(), false);
1303 QCOMPARE(textObject->font().underline(), false);
1304 QCOMPARE(textObject->font().strikeOut(), true);
1307 void tst_qquicktext::capitalization()
1310 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
1311 QQmlComponent textComponent(&engine);
1312 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1313 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1315 QVERIFY(textObject != 0);
1316 QCOMPARE((int)textObject->font().capitalization(), (int)QQuickFontValueType::MixedCase);
1321 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.capitalization: \"AllUppercase\" }";
1322 QQmlComponent textComponent(&engine);
1323 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1324 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1326 QVERIFY(textObject != 0);
1327 QCOMPARE((int)textObject->font().capitalization(), (int)QQuickFontValueType::AllUppercase);
1332 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.capitalization: \"AllLowercase\" }";
1333 QQmlComponent textComponent(&engine);
1334 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1335 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1337 QVERIFY(textObject != 0);
1338 QCOMPARE((int)textObject->font().capitalization(), (int)QQuickFontValueType::AllLowercase);
1343 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.capitalization: \"SmallCaps\" }";
1344 QQmlComponent textComponent(&engine);
1345 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1346 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1348 QVERIFY(textObject != 0);
1349 QCOMPARE((int)textObject->font().capitalization(), (int)QQuickFontValueType::SmallCaps);
1354 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.capitalization: \"Capitalize\" }";
1355 QQmlComponent textComponent(&engine);
1356 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1357 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1359 QVERIFY(textObject != 0);
1360 QCOMPARE((int)textObject->font().capitalization(), (int)QQuickFontValueType::Capitalize);
1366 void tst_qquicktext::letterSpacing()
1369 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
1370 QQmlComponent textComponent(&engine);
1371 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1372 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1374 QVERIFY(textObject != 0);
1375 QCOMPARE(textObject->font().letterSpacing(), 0.0);
1380 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.letterSpacing: -2 }";
1381 QQmlComponent textComponent(&engine);
1382 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1383 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1385 QVERIFY(textObject != 0);
1386 QCOMPARE(textObject->font().letterSpacing(), -2.);
1391 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.letterSpacing: 3 }";
1392 QQmlComponent textComponent(&engine);
1393 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1394 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1396 QVERIFY(textObject != 0);
1397 QCOMPARE(textObject->font().letterSpacing(), 3.);
1403 void tst_qquicktext::wordSpacing()
1406 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
1407 QQmlComponent textComponent(&engine);
1408 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1409 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1411 QVERIFY(textObject != 0);
1412 QCOMPARE(textObject->font().wordSpacing(), 0.0);
1417 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.wordSpacing: -50 }";
1418 QQmlComponent textComponent(&engine);
1419 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1420 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1422 QVERIFY(textObject != 0);
1423 QCOMPARE(textObject->font().wordSpacing(), -50.);
1428 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.wordSpacing: 200 }";
1429 QQmlComponent textComponent(&engine);
1430 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1431 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1433 QVERIFY(textObject != 0);
1434 QCOMPARE(textObject->font().wordSpacing(), 200.);
1443 class EventSender : public QQuickItem
1446 void sendEvent(QMouseEvent *event) {
1447 if (event->type() == QEvent::MouseButtonPress)
1448 mousePressEvent(event);
1449 else if (event->type() == QEvent::MouseButtonRelease)
1450 mouseReleaseEvent(event);
1451 else if (event->type() == QEvent::MouseMove)
1452 mouseMoveEvent(event);
1454 qWarning() << "Trying to send unsupported event type";
1458 class LinkTest : public QObject
1467 void linkClicked(QString l) { link = l; }
1473 TextMetrics(const QString &text, Qt::TextElideMode elideMode = Qt::ElideNone)
1475 QString adjustedText = text;
1476 adjustedText.replace(QLatin1Char('\n'), QChar(QChar::LineSeparator));
1477 if (elideMode == Qt::ElideLeft)
1478 adjustedText = QChar(0x2026) + adjustedText;
1479 else if (elideMode == Qt::ElideRight)
1480 adjustedText = adjustedText + QChar(0x2026);
1482 layout.setText(adjustedText);
1484 option.setUseDesignMetrics(true);
1485 layout.setTextOption(option);
1487 layout.beginLayout();
1489 QTextLine line = layout.createLine();
1490 while (line.isValid()) {
1491 line.setLineWidth(FLT_MAX);
1492 line.setPosition(QPointF(0, height));
1493 height += line.height();
1494 line = layout.createLine();
1499 qreal width() const { return layout.maximumWidth(); }
1501 QRectF characterRectangle(
1503 int hAlign = Qt::AlignLeft,
1504 int vAlign = Qt::AlignTop,
1505 const QSizeF &bounds = QSizeF(240, 320)) const
1509 case Qt::AlignBottom:
1510 dy = bounds.height() - layout.boundingRect().height();
1512 case Qt::AlignVCenter:
1513 dy = (bounds.height() - layout.boundingRect().height()) / 2;
1519 for (int i = 0; i < layout.lineCount(); ++i) {
1520 QTextLine line = layout.lineAt(i);
1521 if (position >= line.textStart() + line.textLength())
1525 case Qt::AlignRight:
1526 dx = bounds.width() - line.naturalTextWidth();
1528 case Qt::AlignHCenter:
1529 dx = (bounds.width() - line.naturalTextWidth()) / 2;
1536 rect.setLeft(dx + line.cursorToX(position, QTextLine::Leading));
1537 rect.setRight(dx + line.cursorToX(position, QTextLine::Trailing));
1538 rect.setTop(dy + line.y());
1539 rect.setBottom(dy + line.y() + line.height());
1550 typedef QVector<QPointF> PointVector;
1551 Q_DECLARE_METATYPE(PointVector);
1553 void tst_qquicktext::clickLink_data()
1555 QTest::addColumn<QString>("text");
1556 QTest::addColumn<qreal>("width");
1557 QTest::addColumn<QString>("bindings");
1558 QTest::addColumn<PointVector>("mousePositions");
1559 QTest::addColumn<QString>("link");
1561 const QString singleLineText = "this text has a <a href=\\\"http://qt-project.org/single\\\">link</a> in it";
1562 const QString singleLineLink = "http://qt-project.org/single";
1563 const QString multipleLineText = "this text<br/>has <a href=\\\"http://qt-project.org/multiple\\\">multiple<br/>lines</a> in it";
1564 const QString multipleLineLink = "http://qt-project.org/multiple";
1565 const QString nestedText = "this text has a <a href=\\\"http://qt-project.org/outer\\\">nested <a href=\\\"http://qt-project.org/inner\\\">link</a> in it</a>";
1566 const QString outerLink = "http://qt-project.org/outer";
1567 const QString innerLink = "http://qt-project.org/inner";
1570 const TextMetrics metrics("this text has a link in it");
1572 QTest::newRow("click on link")
1573 << singleLineText << 240.
1575 << (PointVector() << metrics.characterRectangle(18).center())
1577 QTest::newRow("click on text")
1578 << singleLineText << 240.
1580 << (PointVector() << metrics.characterRectangle(13).center())
1582 QTest::newRow("drag within link")
1583 << singleLineText << 240.
1586 << metrics.characterRectangle(17).center()
1587 << metrics.characterRectangle(19).center())
1589 QTest::newRow("drag away from link")
1590 << singleLineText << 240.
1593 << metrics.characterRectangle(18).center()
1594 << metrics.characterRectangle(13).center())
1596 QTest::newRow("drag on to link")
1597 << singleLineText << 240.
1600 << metrics.characterRectangle(13).center()
1601 << metrics.characterRectangle(18).center())
1603 QTest::newRow("click on bottom right aligned link")
1604 << singleLineText << 240.
1605 << "horizontalAlignment: Text.AlignRight; verticalAlignment: Text.AlignBottom"
1606 << (PointVector() << metrics.characterRectangle(18, Qt::AlignRight, Qt::AlignBottom).center())
1608 QTest::newRow("click on center aligned link")
1609 << singleLineText << 240.
1610 << "horizontalAlignment: Text.AlignHCenter; verticalAlignment: Text.AlignVCenter"
1611 << (PointVector() << metrics.characterRectangle(18, Qt::AlignHCenter, Qt::AlignVCenter).center())
1613 QTest::newRow("click on rich text link")
1614 << singleLineText << 240.
1615 << "textFormat: Text.RichText"
1616 << (PointVector() << metrics.characterRectangle(18).center())
1618 QTest::newRow("click on rich text")
1619 << singleLineText << 240.
1620 << "textFormat: Text.RichText"
1621 << (PointVector() << metrics.characterRectangle(13).center())
1623 QTest::newRow("click on bottom right aligned rich text link")
1624 << singleLineText << 240.
1625 << "textFormat: Text.RichText; horizontalAlignment: Text.AlignRight; verticalAlignment: Text.AlignBottom"
1626 << (PointVector() << metrics.characterRectangle(18, Qt::AlignRight, Qt::AlignBottom).center())
1628 QTest::newRow("click on center aligned rich text link")
1629 << singleLineText << 240.
1630 << "textFormat: Text.RichText; horizontalAlignment: Text.AlignHCenter; verticalAlignment: Text.AlignVCenter"
1631 << (PointVector() << metrics.characterRectangle(18, Qt::AlignHCenter, Qt::AlignVCenter).center())
1634 const TextMetrics metrics("this text has a li", Qt::ElideRight);
1635 QTest::newRow("click on right elided link")
1636 << singleLineText << metrics.width() + 2
1637 << "elide: Text.ElideRight"
1638 << (PointVector() << metrics.characterRectangle(17).center())
1641 const TextMetrics metrics("ink in it", Qt::ElideLeft);
1642 QTest::newRow("click on left elided link")
1643 << singleLineText << metrics.width() + 2
1644 << "elide: Text.ElideLeft"
1645 << (PointVector() << metrics.characterRectangle(2).center())
1648 const TextMetrics metrics("this text\nhas multiple\nlines in it");
1649 QTest::newRow("click on second line")
1650 << multipleLineText << 240.
1652 << (PointVector() << metrics.characterRectangle(18).center())
1653 << multipleLineLink;
1654 QTest::newRow("click on third line")
1655 << multipleLineText << 240.
1657 << (PointVector() << metrics.characterRectangle(25).center())
1658 << multipleLineLink;
1659 QTest::newRow("drag from second line to third")
1660 << multipleLineText << 240.
1663 << metrics.characterRectangle(18).center()
1664 << metrics.characterRectangle(25).center())
1665 << multipleLineLink;
1666 QTest::newRow("click on rich text second line")
1667 << multipleLineText << 240.
1668 << "textFormat: Text.RichText"
1669 << (PointVector() << metrics.characterRectangle(18).center())
1670 << multipleLineLink;
1671 QTest::newRow("click on rich text third line")
1672 << multipleLineText << 240.
1673 << "textFormat: Text.RichText"
1674 << (PointVector() << metrics.characterRectangle(25).center())
1675 << multipleLineLink;
1676 QTest::newRow("drag rich text from second line to third")
1677 << multipleLineText << 240.
1678 << "textFormat: Text.RichText"
1680 << metrics.characterRectangle(18).center()
1681 << metrics.characterRectangle(25).center())
1682 << multipleLineLink;
1684 const TextMetrics metrics("this text has a nested link in it");
1685 QTest::newRow("click on left outer link")
1686 << nestedText << 240.
1688 << (PointVector() << metrics.characterRectangle(22).center())
1690 QTest::newRow("click on right outer link")
1691 << nestedText << 240.
1693 << (PointVector() << metrics.characterRectangle(27).center())
1695 QTest::newRow("click on inner link left")
1696 << nestedText << 240.
1698 << (PointVector() << metrics.characterRectangle(23).center())
1700 QTest::newRow("click on inner link right")
1701 << nestedText << 240.
1703 << (PointVector() << metrics.characterRectangle(26).center())
1705 QTest::newRow("drag from inner to outer link")
1706 << nestedText << 240.
1709 << metrics.characterRectangle(25).center()
1710 << metrics.characterRectangle(30).center())
1712 QTest::newRow("drag from outer to inner link")
1713 << nestedText << 240.
1716 << metrics.characterRectangle(30).center()
1717 << metrics.characterRectangle(25).center())
1719 QTest::newRow("click on left outer rich text link")
1720 << nestedText << 240.
1721 << "textFormat: Text.RichText"
1722 << (PointVector() << metrics.characterRectangle(22).center())
1724 QTest::newRow("click on right outer rich text link")
1725 << nestedText << 240.
1726 << "textFormat: Text.RichText"
1727 << (PointVector() << metrics.characterRectangle(27).center())
1729 QTest::newRow("click on inner rich text link left")
1730 << nestedText << 240.
1731 << "textFormat: Text.RichText"
1732 << (PointVector() << metrics.characterRectangle(23).center())
1734 QTest::newRow("click on inner rich text link right")
1735 << nestedText << 240.
1736 << "textFormat: Text.RichText"
1737 << (PointVector() << metrics.characterRectangle(26).center())
1739 QTest::newRow("drag from inner to outer rich text link")
1740 << nestedText << 240.
1741 << "textFormat: Text.RichText"
1743 << metrics.characterRectangle(25).center()
1744 << metrics.characterRectangle(30).center())
1746 QTest::newRow("drag from outer to inner rich text link")
1747 << nestedText << 240.
1748 << "textFormat: Text.RichText"
1750 << metrics.characterRectangle(30).center()
1751 << metrics.characterRectangle(25).center())
1756 void tst_qquicktext::clickLink()
1758 QFETCH(QString, text);
1759 QFETCH(qreal, width);
1760 QFETCH(QString, bindings);
1761 QFETCH(PointVector, mousePositions);
1762 QFETCH(QString, link);
1764 QString componentStr =
1765 "import QtQuick 2.0\nText {\n"
1766 "width: " + QString::number(width) + "\n"
1768 "text: \"" + text + "\"\n"
1769 "" + bindings + "\n"
1771 QQmlComponent textComponent(&engine);
1772 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1773 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1775 QVERIFY(textObject != 0);
1778 QObject::connect(textObject, SIGNAL(linkActivated(QString)), &test, SLOT(linkClicked(QString)));
1780 QVERIFY(mousePositions.count() > 0);
1782 QPointF mousePosition = mousePositions.first();
1784 QMouseEvent me(QEvent::MouseButtonPress, mousePosition, Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
1785 static_cast<EventSender*>(static_cast<QQuickItem*>(textObject))->sendEvent(&me);
1788 for (int i = 1; i < mousePositions.count(); ++i) {
1789 mousePosition = mousePositions.at(i);
1791 QMouseEvent me(QEvent::MouseMove, mousePosition, Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
1792 static_cast<EventSender*>(static_cast<QQuickItem*>(textObject))->sendEvent(&me);
1796 QMouseEvent me(QEvent::MouseButtonRelease, mousePosition, Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
1797 static_cast<EventSender*>(static_cast<QQuickItem*>(textObject))->sendEvent(&me);
1800 QCOMPARE(test.link, link);
1805 void tst_qquicktext::baseUrl()
1807 QUrl localUrl("file:///tests/text.qml");
1808 QUrl remoteUrl("http://qt.nokia.com/test.qml");
1810 QQmlComponent textComponent(&engine);
1811 textComponent.setData("import QtQuick 2.0\n Text {}", localUrl);
1812 QQuickText *textObject = qobject_cast<QQuickText *>(textComponent.create());
1814 QCOMPARE(textObject->baseUrl(), localUrl);
1816 QSignalSpy spy(textObject, SIGNAL(baseUrlChanged()));
1818 textObject->setBaseUrl(localUrl);
1819 QCOMPARE(textObject->baseUrl(), localUrl);
1820 QCOMPARE(spy.count(), 0);
1822 textObject->setBaseUrl(remoteUrl);
1823 QCOMPARE(textObject->baseUrl(), remoteUrl);
1824 QCOMPARE(spy.count(), 1);
1826 textObject->resetBaseUrl();
1827 QCOMPARE(textObject->baseUrl(), localUrl);
1828 QCOMPARE(spy.count(), 2);
1831 void tst_qquicktext::embeddedImages_data()
1833 QTest::addColumn<QUrl>("qmlfile");
1834 QTest::addColumn<QString>("error");
1835 QTest::newRow("local") << testFileUrl("embeddedImagesLocal.qml") << "";
1836 QTest::newRow("local-error") << testFileUrl("embeddedImagesLocalError.qml")
1837 << testFileUrl("embeddedImagesLocalError.qml").toString()+":3:1: QML Text: Cannot open: " + testFileUrl("http/notexists.png").toString();
1838 QTest::newRow("local") << testFileUrl("embeddedImagesLocalRelative.qml") << "";
1839 QTest::newRow("remote") << testFileUrl("embeddedImagesRemote.qml") << "";
1840 QTest::newRow("remote-error") << testFileUrl("embeddedImagesRemoteError.qml")
1841 << testFileUrl("embeddedImagesRemoteError.qml").toString()+":3:1: QML Text: Error downloading " SERVER_ADDR "/notexists.png - server replied: Not found";
1842 QTest::newRow("remote") << testFileUrl("embeddedImagesRemoteRelative.qml") << "";
1845 void tst_qquicktext::embeddedImages()
1849 QFETCH(QUrl, qmlfile);
1850 QFETCH(QString, error);
1852 TestHTTPServer server(SERVER_PORT);
1853 server.serveDirectory(testFile("http"));
1855 if (!error.isEmpty())
1856 QTest::ignoreMessage(QtWarningMsg, error.toLatin1());
1858 QQuickView *view = new QQuickView(qmlfile);
1860 view->requestActivateWindow();
1861 QTest::qWaitForWindowShown(view);
1862 QQuickText *textObject = qobject_cast<QQuickText*>(view->rootObject());
1864 QVERIFY(textObject != 0);
1865 QTRY_COMPARE(textObject->resourcesLoading(), 0);
1867 QPixmap pm(testFile("http/exists.png"));
1868 if (error.isEmpty()) {
1869 QCOMPARE(textObject->width(), double(pm.width()));
1870 QCOMPARE(textObject->height(), double(pm.height()));
1872 QVERIFY(16 != pm.width()); // check test is effective
1873 QCOMPARE(textObject->width(), 16.0); // default size of QTextDocument broken image icon
1874 QCOMPARE(textObject->height(), 16.0);
1880 void tst_qquicktext::lineCount()
1882 QQuickView *canvas = createView(testFile("lineCount.qml"));
1884 QQuickText *myText = canvas->rootObject()->findChild<QQuickText*>("myText");
1885 QVERIFY(myText != 0);
1887 QVERIFY(myText->lineCount() > 1);
1888 QVERIFY(!myText->truncated());
1889 QCOMPARE(myText->maximumLineCount(), INT_MAX);
1891 myText->setMaximumLineCount(2);
1892 QCOMPARE(myText->lineCount(), 2);
1893 QCOMPARE(myText->truncated(), true);
1894 QCOMPARE(myText->maximumLineCount(), 2);
1896 myText->resetMaximumLineCount();
1897 QCOMPARE(myText->maximumLineCount(), INT_MAX);
1898 QCOMPARE(myText->truncated(), false);
1900 myText->setElideMode(QQuickText::ElideRight);
1901 myText->setMaximumLineCount(2);
1902 QCOMPARE(myText->lineCount(), 2);
1903 QCOMPARE(myText->truncated(), true);
1904 QCOMPARE(myText->maximumLineCount(), 2);
1909 void tst_qquicktext::lineHeight()
1911 QQuickView *canvas = createView(testFile("lineHeight.qml"));
1913 QQuickText *myText = canvas->rootObject()->findChild<QQuickText*>("myText");
1914 QVERIFY(myText != 0);
1916 QVERIFY(myText->lineHeight() == 1);
1917 QVERIFY(myText->lineHeightMode() == QQuickText::ProportionalHeight);
1919 qreal h = myText->height();
1920 myText->setLineHeight(1.5);
1921 QCOMPARE(myText->height(), qreal(qCeil(h)) * 1.5);
1923 myText->setLineHeightMode(QQuickText::FixedHeight);
1924 myText->setLineHeight(20);
1925 QCOMPARE(myText->height(), myText->lineCount() * 20.0);
1927 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.");
1928 myText->setLineHeightMode(QQuickText::ProportionalHeight);
1929 myText->setLineHeight(1.0);
1931 qreal h2 = myText->height();
1932 myText->setLineHeight(2.0);
1933 QVERIFY(myText->height() == h2 * 2.0);
1935 myText->setLineHeightMode(QQuickText::FixedHeight);
1936 myText->setLineHeight(10);
1937 QCOMPARE(myText->height(), myText->lineCount() * 10.0);
1942 void tst_qquicktext::implicitSize_data()
1944 QTest::addColumn<QString>("text");
1945 QTest::addColumn<QString>("width");
1946 QTest::addColumn<QString>("wrap");
1947 QTest::addColumn<QString>("elide");
1948 QTest::addColumn<QString>("format");
1949 QTest::newRow("plain") << "The quick red fox jumped over the lazy brown dog" << "50" << "Text.NoWrap" << "Text.ElideNone" << "Text.PlainText";
1950 QTest::newRow("richtext") << "<b>The quick red fox jumped over the lazy brown dog</b>" <<" 50" << "Text.NoWrap" << "Text.ElideNone" << "Text.RichText";
1951 QTest::newRow("styledtext") << "<b>The quick red fox jumped over the lazy brown dog</b>" <<" 50" << "Text.NoWrap" << "Text.ElideNone" << "Text.StyledText";
1952 QTest::newRow("plain, 0 width") << "The quick red fox jumped over the lazy brown dog" << "0" << "Text.NoWrap" << "Text.ElideNone" << "Text.PlainText";
1953 QTest::newRow("plain, elide") << "The quick red fox jumped over the lazy brown dog" << "50" << "Text.NoWrap" << "Text.ElideRight" << "Text.PlainText";
1954 QTest::newRow("plain, 0 width, elide") << "The quick red fox jumped over the lazy brown dog" << "0" << "Text.NoWrap" << "Text.ElideRight" << "Text.PlainText";
1955 QTest::newRow("richtext, 0 width") << "<b>The quick red fox jumped over the lazy brown dog</b>" <<" 0" << "Text.NoWrap" << "Text.ElideNone" << "Text.RichText";
1956 QTest::newRow("styledtext, 0 width") << "<b>The quick red fox jumped over the lazy brown dog</b>" <<" 0" << "Text.NoWrap" << "Text.ElideNone" << "Text.StyledText";
1957 QTest::newRow("plain_wrap") << "The quick red fox jumped over the lazy brown dog" << "50" << "Text.Wrap" << "Text.ElideNone" << "Text.PlainText";
1958 QTest::newRow("richtext_wrap") << "<b>The quick red fox jumped over the lazy brown dog</b>" << "50" << "Text.Wrap" << "Text.ElideNone" << "Text.RichText";
1959 QTest::newRow("styledtext_wrap") << "<b>The quick red fox jumped over the lazy brown dog</b>" << "50" << "Text.Wrap" << "Text.ElideNone" << "Text.StyledText";
1960 QTest::newRow("plain_wrap, 0 width") << "The quick red fox jumped over the lazy brown dog" << "0" << "Text.Wrap" << "Text.ElideNone" << "Text.PlainText";
1961 QTest::newRow("plain_wrap, elide") << "The quick red fox jumped over the lazy brown dog" << "50" << "Text.Wrap" << "Text.ElideRight" << "Text.PlainText";
1962 QTest::newRow("plain_wrap, 0 width, elide") << "The quick red fox jumped over the lazy brown dog" << "0" << "Text.Wrap" << "Text.ElideRight" << "Text.PlainText";
1963 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";
1964 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";
1967 void tst_qquicktext::implicitSize()
1969 QFETCH(QString, text);
1970 QFETCH(QString, width);
1971 QFETCH(QString, format);
1972 QFETCH(QString, wrap);
1973 QFETCH(QString, elide);
1974 QString componentStr = "import QtQuick 2.0\nText { "
1975 "property real iWidth: implicitWidth; "
1976 "text: \"" + text + "\"; "
1977 "width: " + width + "; "
1978 "textFormat: " + format + "; "
1979 "wrapMode: " + wrap + "; "
1980 "elide: " + elide + "; "
1981 "maximumLineCount: 2 }";
1982 QQmlComponent textComponent(&engine);
1983 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1984 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1986 QVERIFY(textObject->width() < textObject->implicitWidth());
1987 QVERIFY(textObject->height() == textObject->implicitHeight());
1988 QCOMPARE(textObject->property("iWidth").toReal(), textObject->implicitWidth());
1990 textObject->resetWidth();
1991 QVERIFY(textObject->width() == textObject->implicitWidth());
1992 QVERIFY(textObject->height() == textObject->implicitHeight());
1997 void tst_qquicktext::contentSize()
1999 QString componentStr = "import QtQuick 2.0\nText { width: 75; height: 16; font.pixelSize: 10 }";
2000 QQmlComponent textComponent(&engine);
2001 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
2002 QScopedPointer<QObject> object(textComponent.create());
2003 QQuickText *textObject = qobject_cast<QQuickText *>(object.data());
2005 QSignalSpy spy(textObject, SIGNAL(contentSizeChanged()));
2007 textObject->setText("The quick red fox jumped over the lazy brown dog");
2009 QVERIFY(textObject->contentWidth() > textObject->width());
2010 QVERIFY(textObject->contentHeight() < textObject->height());
2011 QCOMPARE(spy.count(), 1);
2013 textObject->setWrapMode(QQuickText::WordWrap);
2014 QVERIFY(textObject->contentWidth() <= textObject->width());
2015 QVERIFY(textObject->contentHeight() > textObject->height());
2016 QCOMPARE(spy.count(), 2);
2018 textObject->setElideMode(QQuickText::ElideRight);
2019 QVERIFY(textObject->contentWidth() <= textObject->width());
2020 QVERIFY(textObject->contentHeight() < textObject->height());
2021 QCOMPARE(spy.count(), 3);
2023 qreal elidedWidth = textObject->contentWidth();
2025 textObject->setText("The quickredfoxjumpedoverthe lazy brown dog");
2026 QVERIFY(textObject->contentWidth() <= textObject->width());
2027 QVERIFY(textObject->contentHeight() < textObject->height());
2028 // this text probably won't have the same elided width, but it's not guaranteed.
2029 if (textObject->contentWidth() != elidedWidth)
2030 QCOMPARE(spy.count(), ++spyCount);
2032 QCOMPARE(spy.count(), spyCount);
2034 textObject->setElideMode(QQuickText::ElideNone);
2035 QVERIFY(textObject->contentWidth() > textObject->width());
2036 QVERIFY(textObject->contentHeight() > textObject->height());
2037 QCOMPARE(spy.count(), ++spyCount);
2040 void tst_qquicktext::geometryChanged()
2042 // Test that text is re-laid out when the geometry of the item by verifying changes in content
2043 // size. Implicit width is also tested as that in combination with item geometry provides a
2044 // reference for expected content sizes.
2046 QString componentStr = "import QtQuick 2.0\nText { font.family: \"__Qt__Box__Engine__\"; font.pixelSize: 10 }";
2047 QQmlComponent textComponent(&engine);
2048 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
2049 QScopedPointer<QObject> object(textComponent.create());
2050 QQuickText *textObject = qobject_cast<QQuickText *>(object.data());
2052 const qreal implicitHeight = textObject->implicitHeight();
2054 const qreal widths[] = { 100, 2000, 3000, -100, 100 };
2055 const qreal heights[] = { implicitHeight, 2000, 3000, -implicitHeight, implicitHeight };
2057 QCOMPARE(textObject->implicitWidth(), 0.);
2058 QVERIFY(implicitHeight > 0.);
2059 QCOMPARE(textObject->width(), textObject->implicitWidth());
2060 QCOMPARE(textObject->height(), implicitHeight);
2061 QCOMPARE(textObject->contentWidth(), textObject->implicitWidth());
2062 QCOMPARE(textObject->contentHeight(), implicitHeight);
2064 textObject->setText("The quick red fox jumped over the lazy brown dog");
2066 const qreal implicitWidth = textObject->implicitWidth();
2068 QVERIFY(implicitWidth > 0.);
2069 QCOMPARE(textObject->implicitHeight(), implicitHeight);
2070 QCOMPARE(textObject->width(), textObject->implicitWidth());
2071 QCOMPARE(textObject->height(), textObject->implicitHeight());
2072 QCOMPARE(textObject->contentWidth(), textObject->implicitWidth());
2073 QCOMPARE(textObject->contentHeight(), textObject->implicitHeight());
2075 // Changing the geometry with no eliding, or wrapping doesn't change the content size.
2076 for (int i = 0; i < 5; ++i) {
2077 textObject->setWidth(widths[i]);
2078 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2079 QCOMPARE(textObject->implicitHeight(), implicitHeight);
2080 QCOMPARE(textObject->width(), widths[i]);
2081 QCOMPARE(textObject->height(), implicitHeight);
2082 QCOMPARE(textObject->contentWidth(), implicitWidth);
2083 QCOMPARE(textObject->contentHeight(), implicitHeight);
2086 // With eliding enabled the content width is bounded to the item width, but is never
2087 // larger than the implicit width.
2088 textObject->setElideMode(QQuickText::ElideRight);
2089 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2090 QCOMPARE(textObject->implicitHeight(), implicitHeight);
2091 QCOMPARE(textObject->width(), 100.);
2092 QCOMPARE(textObject->height(), implicitHeight);
2093 QVERIFY(textObject->contentWidth() <= 100.);
2094 QCOMPARE(textObject->contentHeight(), implicitHeight);
2096 textObject->setWidth(2000.);
2097 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2098 QCOMPARE(textObject->implicitHeight(), implicitHeight);
2099 QCOMPARE(textObject->width(), 2000.);
2100 QCOMPARE(textObject->height(), implicitHeight);
2101 QCOMPARE(textObject->contentWidth(), implicitWidth);
2102 QCOMPARE(textObject->contentHeight(), implicitHeight);
2104 textObject->setWidth(3000.);
2105 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2106 QCOMPARE(textObject->implicitHeight(), implicitHeight);
2107 QCOMPARE(textObject->width(), 3000.);
2108 QCOMPARE(textObject->height(), implicitHeight);
2109 QCOMPARE(textObject->contentWidth(), implicitWidth);
2110 QCOMPARE(textObject->contentHeight(), implicitHeight);
2112 textObject->setWidth(-100);
2113 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2114 QCOMPARE(textObject->implicitHeight(), implicitHeight);
2115 QCOMPARE(textObject->width(), -100.);
2116 QCOMPARE(textObject->height(), implicitHeight);
2117 QCOMPARE(textObject->contentWidth(), 0.);
2118 QCOMPARE(textObject->contentHeight(), implicitHeight);
2120 textObject->setWidth(100.);
2121 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2122 QCOMPARE(textObject->implicitHeight(), implicitHeight);
2123 QCOMPARE(textObject->width(), 100.);
2124 QCOMPARE(textObject->height(), implicitHeight);
2125 QVERIFY(textObject->contentWidth() <= 100.);
2126 QCOMPARE(textObject->contentHeight(), implicitHeight);
2128 // With wrapping enabled the implicit height changes with the width.
2129 textObject->setElideMode(QQuickText::ElideNone);
2130 textObject->setWrapMode(QQuickText::Wrap);
2131 const qreal wrappedImplicitHeight = textObject->implicitHeight();
2133 QVERIFY(wrappedImplicitHeight > implicitHeight);
2135 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2136 QCOMPARE(textObject->width(), 100.);
2137 QCOMPARE(textObject->height(), wrappedImplicitHeight);
2138 QVERIFY(textObject->contentWidth() <= 100.);
2139 QCOMPARE(textObject->contentHeight(), wrappedImplicitHeight);
2141 textObject->setWidth(2000.);
2142 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2143 QCOMPARE(textObject->implicitHeight(), implicitHeight);
2144 QCOMPARE(textObject->width(), 2000.);
2145 QCOMPARE(textObject->height(), implicitHeight);
2146 QCOMPARE(textObject->contentWidth(), implicitWidth);
2147 QCOMPARE(textObject->contentHeight(), implicitHeight);
2149 textObject->setWidth(3000.);
2150 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2151 QCOMPARE(textObject->implicitHeight(), implicitHeight);
2152 QCOMPARE(textObject->width(), 3000.);
2153 QCOMPARE(textObject->height(), implicitHeight);
2154 QCOMPARE(textObject->contentWidth(), implicitWidth);
2155 QCOMPARE(textObject->contentHeight(), implicitHeight);
2157 textObject->setWidth(-100);
2158 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2159 QCOMPARE(textObject->implicitHeight(), implicitHeight);
2160 QCOMPARE(textObject->width(), -100.);
2161 QCOMPARE(textObject->height(), implicitHeight);
2162 QCOMPARE(textObject->contentWidth(), implicitWidth); // 0 or negative width item won't wrap.
2163 QCOMPARE(textObject->contentHeight(), implicitHeight);
2165 textObject->setWidth(100.);
2166 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2167 QCOMPARE(textObject->implicitHeight(), wrappedImplicitHeight);
2168 QCOMPARE(textObject->width(), 100.);
2169 QCOMPARE(textObject->height(), wrappedImplicitHeight);
2170 QVERIFY(textObject->contentWidth() <= 100.);
2171 QCOMPARE(textObject->contentHeight(), wrappedImplicitHeight);
2173 // With no eliding or maximum line count the content height is the same as the implicit height.
2174 for (int i = 0; i < 5; ++i) {
2175 textObject->setHeight(heights[i]);
2176 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2177 QCOMPARE(textObject->implicitHeight(), wrappedImplicitHeight);
2178 QCOMPARE(textObject->width(), 100.);
2179 QCOMPARE(textObject->height(), heights[i]);
2180 QVERIFY(textObject->contentWidth() <= 100.);
2181 QCOMPARE(textObject->contentHeight(), wrappedImplicitHeight);
2184 // The implicit height is unaffected by eliding but the content height will change.
2185 textObject->setElideMode(QQuickText::ElideRight);
2187 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2188 QCOMPARE(textObject->implicitHeight(), wrappedImplicitHeight);
2189 QCOMPARE(textObject->width(), 100.);
2190 QCOMPARE(textObject->height(), implicitHeight);
2191 QVERIFY(textObject->contentWidth() <= 100.);
2192 QCOMPARE(textObject->contentHeight(), implicitHeight);
2194 textObject->setHeight(2000);
2195 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2196 QCOMPARE(textObject->implicitHeight(), wrappedImplicitHeight);
2197 QCOMPARE(textObject->width(), 100.);
2198 QCOMPARE(textObject->height(), 2000.);
2199 QVERIFY(textObject->contentWidth() <= 100.);
2200 QCOMPARE(textObject->contentHeight(), wrappedImplicitHeight);
2202 textObject->setHeight(3000);
2203 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2204 QCOMPARE(textObject->implicitHeight(), wrappedImplicitHeight);
2205 QCOMPARE(textObject->width(), 100.);
2206 QCOMPARE(textObject->height(), 3000.);
2207 QVERIFY(textObject->contentWidth() <= 100.);
2208 QCOMPARE(textObject->contentHeight(), wrappedImplicitHeight);
2210 textObject->setHeight(-implicitHeight);
2211 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2212 QCOMPARE(textObject->implicitHeight(), wrappedImplicitHeight);
2213 QCOMPARE(textObject->width(), 100.);
2214 QCOMPARE(textObject->height(), -implicitHeight);
2215 QVERIFY(textObject->contentWidth() <= 0.);
2216 QCOMPARE(textObject->contentHeight(), implicitHeight); // content height is never less than font height. seems a little odd in this instance.
2218 textObject->setHeight(implicitHeight);
2219 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2220 QCOMPARE(textObject->implicitHeight(), wrappedImplicitHeight);
2221 QCOMPARE(textObject->width(), 100.);
2222 QCOMPARE(textObject->height(), implicitHeight);
2223 QVERIFY(textObject->contentWidth() <= 100.);
2224 QCOMPARE(textObject->contentHeight(), implicitHeight);
2226 // Varying the height with a maximum line count but no eliding won't affect the content height.
2227 textObject->setElideMode(QQuickText::ElideNone);
2228 textObject->setMaximumLineCount(2);
2229 textObject->resetHeight();
2231 const qreal maxLineCountImplicitHeight = textObject->implicitHeight();
2232 QVERIFY(maxLineCountImplicitHeight > implicitHeight);
2233 QVERIFY(maxLineCountImplicitHeight < wrappedImplicitHeight);
2235 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2236 QCOMPARE(textObject->width(), 100.);
2237 QCOMPARE(textObject->height(), maxLineCountImplicitHeight);
2238 QVERIFY(textObject->contentWidth() <= 100.);
2239 QCOMPARE(textObject->contentHeight(), maxLineCountImplicitHeight);
2241 for (int i = 0; i < 5; ++i) {
2242 textObject->setHeight(heights[i]);
2243 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2244 QCOMPARE(textObject->implicitHeight(), maxLineCountImplicitHeight);
2245 QCOMPARE(textObject->width(), 100.);
2246 QCOMPARE(textObject->height(), heights[i]);
2247 QVERIFY(textObject->contentWidth() <= 100.);
2248 QCOMPARE(textObject->contentHeight(), maxLineCountImplicitHeight);
2251 // Varying the width with a maximum line count won't increase the implicit height beyond the
2252 // height of the maximum number of lines.
2253 textObject->setWidth(2000.);
2254 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2255 QCOMPARE(textObject->implicitHeight(), implicitHeight);
2256 QCOMPARE(textObject->width(), 2000.);
2257 QCOMPARE(textObject->height(), implicitHeight);
2258 QCOMPARE(textObject->contentWidth(), implicitWidth);
2259 QCOMPARE(textObject->contentHeight(), implicitHeight);
2261 textObject->setWidth(3000.);
2262 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2263 QCOMPARE(textObject->implicitHeight(), implicitHeight);
2264 QCOMPARE(textObject->width(), 3000.);
2265 QCOMPARE(textObject->height(), implicitHeight);
2266 QCOMPARE(textObject->contentWidth(), implicitWidth);
2267 QCOMPARE(textObject->contentHeight(), implicitHeight);
2269 textObject->setWidth(-100);
2270 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2271 QCOMPARE(textObject->implicitHeight(), implicitHeight);
2272 QCOMPARE(textObject->width(), -100.);
2273 QCOMPARE(textObject->height(), implicitHeight);
2274 QCOMPARE(textObject->contentWidth(), implicitWidth); // 0 or negative width item won't wrap.
2275 QCOMPARE(textObject->contentHeight(), implicitHeight);
2277 textObject->setWidth(50.);
2278 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2279 QCOMPARE(textObject->implicitHeight(), maxLineCountImplicitHeight);
2280 QCOMPARE(textObject->width(), 50.);
2281 QCOMPARE(textObject->height(), implicitHeight);
2282 QVERIFY(textObject->contentWidth() <= 50.);
2283 QCOMPARE(textObject->contentHeight(), maxLineCountImplicitHeight);
2285 textObject->setWidth(100.);
2286 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2287 QCOMPARE(textObject->implicitHeight(), maxLineCountImplicitHeight);
2288 QCOMPARE(textObject->width(), 100.);
2289 QCOMPARE(textObject->height(), implicitHeight);
2290 QVERIFY(textObject->contentWidth() <= 100.);
2291 QCOMPARE(textObject->contentHeight(), maxLineCountImplicitHeight);
2294 void tst_qquicktext::implicitSizeBinding_data()
2296 implicitSize_data();
2299 void tst_qquicktext::implicitSizeBinding()
2301 QFETCH(QString, text);
2302 QFETCH(QString, wrap);
2303 QFETCH(QString, format);
2304 QString componentStr = "import QtQuick 2.0\nText { text: \"" + text + "\"; width: implicitWidth; height: implicitHeight; wrapMode: " + wrap + "; textFormat: " + format + " }";
2306 QQmlComponent textComponent(&engine);
2307 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
2308 QScopedPointer<QObject> object(textComponent.create());
2309 QQuickText *textObject = qobject_cast<QQuickText *>(object.data());
2311 QCOMPARE(textObject->width(), textObject->implicitWidth());
2312 QCOMPARE(textObject->height(), textObject->implicitHeight());
2314 textObject->resetWidth();
2315 QCOMPARE(textObject->width(), textObject->implicitWidth());
2316 QCOMPARE(textObject->height(), textObject->implicitHeight());
2318 textObject->resetHeight();
2319 QCOMPARE(textObject->width(), textObject->implicitWidth());
2320 QCOMPARE(textObject->height(), textObject->implicitHeight());
2323 void tst_qquicktext::boundingRect_data()
2325 QTest::addColumn<QString>("format");
2326 QTest::newRow("PlainText") << "Text.PlainText";
2327 QTest::newRow("StyledText") << "Text.StyledText";
2328 QTest::newRow("RichText") << "Text.RichText";
2331 void tst_qquicktext::boundingRect()
2333 QFETCH(QString, format);
2335 QQmlComponent component(&engine);
2336 component.setData("import QtQuick 2.0\n Text { textFormat:" + format.toUtf8() + "}", QUrl());
2337 QScopedPointer<QObject> object(component.create());
2338 QQuickText *text = qobject_cast<QQuickText *>(object.data());
2341 QCOMPARE(text->boundingRect().x(), qreal(0));
2342 QCOMPARE(text->boundingRect().y(), qreal(0));
2343 QCOMPARE(text->boundingRect().width(), qreal(0));
2344 QCOMPARE(text->boundingRect().height(), qreal(qCeil(QFontMetricsF(text->font()).height())));
2346 text->setText("Hello World");
2348 QTextLayout layout(text->text());
2349 layout.setFont(text->font());
2351 if (!qmlDisableDistanceField()) {
2353 option.setUseDesignMetrics(true);
2354 layout.setTextOption(option);
2356 layout.beginLayout();
2357 QTextLine line = layout.createLine();
2360 QCOMPARE(text->boundingRect().x(), qreal(0));
2361 QCOMPARE(text->boundingRect().y(), qreal(0));
2362 QCOMPARE(text->boundingRect().width(), line.naturalTextWidth());
2363 QCOMPARE(text->boundingRect().height(), line.height());
2365 // the size of the bounding rect shouldn't be bounded by the size of item.
2366 text->setWidth(text->width() / 2);
2367 QCOMPARE(text->boundingRect().x(), qreal(0));
2368 QCOMPARE(text->boundingRect().y(), qreal(0));
2369 QCOMPARE(text->boundingRect().width(), line.naturalTextWidth());
2370 QCOMPARE(text->boundingRect().height(), line.height());
2372 text->setHeight(text->height() * 2);
2373 QCOMPARE(text->boundingRect().x(), qreal(0));
2374 QCOMPARE(text->boundingRect().y(), qreal(0));
2375 QCOMPARE(text->boundingRect().width(), line.naturalTextWidth());
2376 QCOMPARE(text->boundingRect().height(), line.height());
2378 text->setHAlign(QQuickText::AlignRight);
2379 QCOMPARE(text->boundingRect().x(), text->width() - line.naturalTextWidth());
2380 QCOMPARE(text->boundingRect().y(), qreal(0));
2381 QCOMPARE(text->boundingRect().width(), line.naturalTextWidth());
2382 QCOMPARE(text->boundingRect().height(), line.height());
2384 text->setWrapMode(QQuickText::Wrap);
2385 QCOMPARE(text->boundingRect().right(), text->width());
2386 QCOMPARE(text->boundingRect().y(), qreal(0));
2387 QVERIFY(text->boundingRect().width() < line.naturalTextWidth());
2388 QVERIFY(text->boundingRect().height() > line.height());
2390 text->setVAlign(QQuickText::AlignBottom);
2391 QCOMPARE(text->boundingRect().right(), text->width());
2392 QCOMPARE(text->boundingRect().bottom(), text->height());
2393 QVERIFY(text->boundingRect().width() < line.naturalTextWidth());
2394 QVERIFY(text->boundingRect().height() > line.height());
2397 void tst_qquicktext::clipRect()
2399 QQmlComponent component(&engine);
2400 component.setData("import QtQuick 2.0\n Text {}", QUrl());
2401 QScopedPointer<QObject> object(component.create());
2402 QQuickText *text = qobject_cast<QQuickText *>(object.data());
2406 layout.setFont(text->font());
2408 QCOMPARE(text->clipRect().x(), qreal(0));
2409 QCOMPARE(text->clipRect().y(), qreal(0));
2410 QCOMPARE(text->clipRect().width(), text->width());
2411 QCOMPARE(text->clipRect().height(), text->height());
2413 text->setText("Hello World");
2415 QCOMPARE(text->clipRect().x(), qreal(0));
2416 QCOMPARE(text->clipRect().y(), qreal(0));
2417 QCOMPARE(text->clipRect().width(), text->width());
2418 QCOMPARE(text->clipRect().height(), text->height());
2420 // Clip rect follows the item not content dimensions.
2421 text->setWidth(text->width() / 2);
2422 QCOMPARE(text->clipRect().x(), qreal(0));
2423 QCOMPARE(text->clipRect().y(), qreal(0));
2424 QCOMPARE(text->clipRect().width(), text->width());
2425 QCOMPARE(text->clipRect().height(), text->height());
2427 text->setHeight(text->height() * 2);
2428 QCOMPARE(text->clipRect().x(), qreal(0));
2429 QCOMPARE(text->clipRect().y(), qreal(0));
2430 QCOMPARE(text->clipRect().width(), text->width());
2431 QCOMPARE(text->clipRect().height(), text->height());
2433 // Setting a style adds a small amount of padding to the clip rect.
2434 text->setStyle(QQuickText::Outline);
2435 QCOMPARE(text->clipRect().x(), qreal(-1));
2436 QCOMPARE(text->clipRect().y(), qreal(0));
2437 QCOMPARE(text->clipRect().width(), text->width() + 2);
2438 QCOMPARE(text->clipRect().height(), text->height() + 2);
2441 void tst_qquicktext::lineLaidOut()
2443 QQuickView *canvas = createView(testFile("lineLayout.qml"));
2445 QQuickText *myText = canvas->rootObject()->findChild<QQuickText*>("myText");
2446 QVERIFY(myText != 0);
2448 QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(myText);
2449 QVERIFY(textPrivate != 0);
2451 QVERIFY(!textPrivate->extra.isAllocated());
2453 for (int i = 0; i < textPrivate->layout.lineCount(); ++i) {
2454 QRectF r = textPrivate->layout.lineAt(i).rect();
2455 QVERIFY(r.width() == i * 15);
2457 QVERIFY(r.x() == r.width() + 30);
2459 QVERIFY(r.x() == r.width() * 2 + 60);
2460 QVERIFY(r.height() == 20);
2467 void tst_qquicktext::lineLaidOutRelayout()
2469 QQuickView *canvas = createView(testFile("lineLayoutRelayout.qml"));
2472 canvas->requestActivateWindow();
2473 QTest::qWaitForWindowShown(canvas);
2475 QQuickText *myText = canvas->rootObject()->findChild<QQuickText*>("myText");
2476 QVERIFY(myText != 0);
2478 QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(myText);
2479 QVERIFY(textPrivate != 0);
2481 QVERIFY(!textPrivate->extra.isAllocated());
2484 for (int i = 0; i < textPrivate->layout.lineCount(); ++i) {
2485 QRectF r = textPrivate->layout.lineAt(i).rect();
2488 QCOMPARE(r.y(), i * r.height());
2489 maxH = qMax(maxH, r.y() + r.height());
2491 QCOMPARE(r.x(), myText->width() / 2);
2492 QCOMPARE(r.y(), (i * r.height()) - maxH);
2499 void tst_qquicktext::imgTagsBaseUrl_data()
2501 QTest::addColumn<QUrl>("src");
2502 QTest::addColumn<QUrl>("baseUrl");
2503 QTest::addColumn<QUrl>("contextUrl");
2504 QTest::addColumn<qreal>("imgHeight");
2506 QTest::newRow("absolute local")
2507 << testFileUrl("images/heart200.png")
2511 QTest::newRow("relative local context 1")
2512 << QUrl("images/heart200.png")
2514 << testFileUrl("/app.qml")
2516 QTest::newRow("relative local context 2")
2517 << QUrl("heart200.png")
2519 << testFileUrl("images/app.qml")
2521 QTest::newRow("relative local base 1")
2522 << QUrl("images/heart200.png")
2524 << testFileUrl("nonexistant/app.qml")
2526 QTest::newRow("relative local base 2")
2527 << QUrl("heart200.png")
2528 << testFileUrl("images/")
2529 << testFileUrl("nonexistant/app.qml")
2531 QTest::newRow("base relative to local context")
2532 << QUrl("heart200.png")
2533 << testFileUrl("images/")
2534 << testFileUrl("/app.qml")
2537 QTest::newRow("absolute remote")
2538 << QUrl(SERVER_ADDR "/images/heart200.png")
2542 QTest::newRow("relative remote base 1")
2543 << QUrl("images/heart200.png")
2544 << QUrl(SERVER_ADDR "/")
2545 << testFileUrl("nonexistant/app.qml")
2547 QTest::newRow("relative remote base 2")
2548 << QUrl("heart200.png")
2549 << QUrl(SERVER_ADDR "/images/")
2550 << testFileUrl("nonexistant/app.qml")
2554 void tst_qquicktext::imgTagsBaseUrl()
2557 QFETCH(QUrl, baseUrl);
2558 QFETCH(QUrl, contextUrl);
2559 QFETCH(qreal, imgHeight);
2561 TestHTTPServer server(SERVER_PORT);
2562 server.serveDirectory(testFile(""));
2564 QByteArray baseUrlFragment;
2565 if (!baseUrl.isEmpty())
2566 baseUrlFragment = "; baseUrl: \"" + baseUrl.toEncoded() + "\"";
2567 QByteArray componentStr = "import QtQuick 2.0\nText { text: \"This is a test <img src=\\\"" + src.toEncoded() + "\\\">\"" + baseUrlFragment + " }";
2569 QQmlComponent component(&engine);
2570 component.setData(componentStr, contextUrl);
2571 QScopedPointer<QObject> object(component.create());
2572 QQuickText *textObject = qobject_cast<QQuickText *>(object.data());
2573 QVERIFY(textObject);
2575 QCoreApplication::processEvents();
2577 QTRY_COMPARE(textObject->height(), imgHeight);
2580 void tst_qquicktext::imgTagsAlign_data()
2582 QTest::addColumn<QString>("src");
2583 QTest::addColumn<int>("imgHeight");
2584 QTest::addColumn<QString>("align");
2585 QTest::newRow("heart-bottom") << "data/images/heart200.png" << 181 << "bottom";
2586 QTest::newRow("heart-middle") << "data/images/heart200.png" << 181 << "middle";
2587 QTest::newRow("heart-top") << "data/images/heart200.png" << 181 << "top";
2588 QTest::newRow("starfish-bottom") << "data/images/starfish_2.png" << 217 << "bottom";
2589 QTest::newRow("starfish-middle") << "data/images/starfish_2.png" << 217 << "middle";
2590 QTest::newRow("starfish-top") << "data/images/starfish_2.png" << 217 << "top";
2593 void tst_qquicktext::imgTagsAlign()
2595 QFETCH(QString, src);
2596 QFETCH(int, imgHeight);
2597 QFETCH(QString, align);
2598 QString componentStr = "import QtQuick 2.0\nText { text: \"This is a test <img src=\\\"" + src + "\\\" align=\\\"" + align + "\\\"> of image.\" }";
2599 QQmlComponent textComponent(&engine);
2600 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
2601 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
2603 QVERIFY(textObject != 0);
2604 QVERIFY(textObject->height() == imgHeight);
2606 QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject);
2607 QVERIFY(textPrivate != 0);
2609 QRectF br = textPrivate->layout.boundingRect();
2610 if (align == "bottom")
2611 QVERIFY(br.y() == imgHeight - br.height());
2612 else if (align == "middle")
2613 QVERIFY(br.y() == imgHeight / 2.0 - br.height() / 2.0);
2614 else if (align == "top")
2615 QVERIFY(br.y() == 0);
2620 void tst_qquicktext::imgTagsMultipleImages()
2622 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\\\">.\" }";
2624 QQmlComponent textComponent(&engine);
2625 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
2626 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
2628 QVERIFY(textObject != 0);
2629 QVERIFY(textObject->height() == 85);
2631 QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject);
2632 QVERIFY(textPrivate != 0);
2633 QVERIFY(textPrivate->visibleImgTags.count() == 2);
2638 void tst_qquicktext::imgTagsElide()
2640 QQuickView *canvas = createView(testFile("imgTagsElide.qml"));
2641 QQuickText *myText = canvas->rootObject()->findChild<QQuickText*>("myText");
2642 QVERIFY(myText != 0);
2644 QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(myText);
2645 QVERIFY(textPrivate != 0);
2646 QVERIFY(textPrivate->visibleImgTags.count() == 0);
2647 myText->setMaximumLineCount(20);
2648 QTRY_VERIFY(textPrivate->visibleImgTags.count() == 1);
2654 void tst_qquicktext::imgTagsUpdates()
2656 QQuickView *canvas = createView(testFile("imgTagsUpdates.qml"));
2657 QQuickText *myText = canvas->rootObject()->findChild<QQuickText*>("myText");
2658 QVERIFY(myText != 0);
2660 QSignalSpy spy(myText, SIGNAL(contentSizeChanged()));
2662 QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(myText);
2663 QVERIFY(textPrivate != 0);
2665 myText->setText("This is a heart<img src=\"images/heart200.png\">.");
2666 QVERIFY(textPrivate->visibleImgTags.count() == 1);
2667 QVERIFY(spy.count() == 1);
2669 myText->setMaximumLineCount(2);
2670 myText->setText("This is another heart<img src=\"images/heart200.png\">.");
2671 QTRY_VERIFY(textPrivate->visibleImgTags.count() == 1);
2673 // if maximumLineCount is set and the img tag doesn't have an explicit size
2674 // we relayout twice.
2675 QVERIFY(spy.count() == 3);
2681 void tst_qquicktext::imgTagsError()
2683 QString componentStr = "import QtQuick 2.0\nText { text: \"This is a starfish<img src=\\\"data/images/starfish_2.pn\\\" width=\\\"60\\\" height=\\\"60\\\">.\" }";
2685 QQmlComponent textComponent(&engine);
2686 QTest::ignoreMessage(QtWarningMsg, "file::2:1: QML Text: Cannot open: file:data/images/starfish_2.pn");
2687 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
2688 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
2690 QVERIFY(textObject != 0);
2694 void tst_qquicktext::fontSizeMode_data()
2696 QTest::addColumn<QString>("text");
2697 QTest::newRow("plain") << "The quick red fox jumped over the lazy brown dog";
2698 QTest::newRow("styled") << "<b>The quick red fox jumped over the lazy brown dog</b>";
2701 void tst_qquicktext::fontSizeMode()
2703 QFETCH(QString, text);
2705 QScopedPointer<QQuickView> canvas(createView(testFile("fontSizeMode.qml")));
2708 QQuickText *myText = canvas->rootObject()->findChild<QQuickText*>("myText");
2709 QVERIFY(myText != 0);
2711 myText->setText(text);
2712 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2714 qreal originalWidth = myText->contentWidth();
2715 qreal originalHeight = myText->contentHeight();
2717 // The original text unwrapped should exceed the width of the item.
2718 QVERIFY(originalWidth > myText->width());
2719 QVERIFY(originalHeight < myText->height());
2721 QFont font = myText->font();
2722 font.setPixelSize(64);
2724 myText->setFont(font);
2725 myText->setFontSizeMode(QQuickText::HorizontalFit);
2726 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2727 // Font size reduced to fit within the width of the item.
2728 qreal horizontalFitWidth = myText->contentWidth();
2729 qreal horizontalFitHeight = myText->contentHeight();
2730 QVERIFY(horizontalFitWidth <= myText->width() + 2); // rounding
2731 QVERIFY(horizontalFitHeight <= myText->height() + 2);
2733 // Elide won't affect the size with HorizontalFit.
2734 myText->setElideMode(QQuickText::ElideRight);
2735 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2736 QVERIFY(!myText->truncated());
2737 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2738 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2740 myText->setElideMode(QQuickText::ElideLeft);
2741 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2742 QVERIFY(!myText->truncated());
2743 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2744 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2746 myText->setElideMode(QQuickText::ElideMiddle);
2747 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2748 QVERIFY(!myText->truncated());
2749 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2750 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2752 myText->setElideMode(QQuickText::ElideNone);
2753 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2755 myText->setFontSizeMode(QQuickText::VerticalFit);
2756 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2757 // Font size increased to fill the height of the item.
2758 qreal verticalFitHeight = myText->contentHeight();
2759 QVERIFY(myText->contentWidth() > myText->width());
2760 QVERIFY(verticalFitHeight <= myText->height() + 2);
2761 QVERIFY(verticalFitHeight > originalHeight);
2763 // Elide won't affect the height of a single line with VerticalFit but will crop the width.
2764 myText->setElideMode(QQuickText::ElideRight);
2765 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2766 QVERIFY(myText->truncated());
2767 QVERIFY(myText->contentWidth() <= myText->width() + 2);
2768 QCOMPARE(myText->contentHeight(), verticalFitHeight);
2770 myText->setElideMode(QQuickText::ElideLeft);
2771 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2772 QVERIFY(myText->truncated());
2773 QVERIFY(myText->contentWidth() <= myText->width() + 2);
2774 QCOMPARE(myText->contentHeight(), verticalFitHeight);
2776 myText->setElideMode(QQuickText::ElideMiddle);
2777 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2778 QVERIFY(myText->truncated());
2779 QVERIFY(myText->contentWidth() <= myText->width() + 2);
2780 QCOMPARE(myText->contentHeight(), verticalFitHeight);
2782 myText->setElideMode(QQuickText::ElideNone);
2783 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2785 myText->setFontSizeMode(QQuickText::Fit);
2786 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2787 // Should be the same as HorizontalFit with no wrapping.
2788 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2789 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2791 // Elide won't affect the size with Fit.
2792 myText->setElideMode(QQuickText::ElideRight);
2793 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2794 QVERIFY(!myText->truncated());
2795 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2796 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2798 myText->setElideMode(QQuickText::ElideLeft);
2799 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2800 QVERIFY(!myText->truncated());
2801 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2802 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2804 myText->setElideMode(QQuickText::ElideMiddle);
2805 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2806 QVERIFY(!myText->truncated());
2807 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2808 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2810 myText->setElideMode(QQuickText::ElideNone);
2811 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2813 myText->setFontSizeMode(QQuickText::FixedSize);
2814 myText->setWrapMode(QQuickText::Wrap);
2815 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2817 originalWidth = myText->contentWidth();
2818 originalHeight = myText->contentHeight();
2820 // The original text wrapped should exceed the height of the item.
2821 QVERIFY(originalWidth <= myText->width() + 2);
2822 QVERIFY(originalHeight > myText->height());
2824 myText->setFontSizeMode(QQuickText::HorizontalFit);
2825 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2826 // HorizontalFit should reduce the font size to minimize wrapping, which brings it back to the
2827 // same size as without text wrapping.
2828 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2829 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2831 // Elide won't affect the size with HorizontalFit.
2832 myText->setElideMode(QQuickText::ElideRight);
2833 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2834 QVERIFY(!myText->truncated());
2835 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2836 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2838 myText->setElideMode(QQuickText::ElideNone);
2839 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2841 myText->setFontSizeMode(QQuickText::VerticalFit);
2842 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2843 // VerticalFit should reduce the size to the wrapped text within the vertical height.
2844 verticalFitHeight = myText->contentHeight();
2845 qreal verticalFitWidth = myText->contentWidth();
2846 QVERIFY(myText->contentWidth() <= myText->width() + 2);
2847 QVERIFY(verticalFitHeight <= myText->height() + 2);
2848 QVERIFY(verticalFitHeight < originalHeight);
2850 // Elide won't affect the height or width of a wrapped text with VerticalFit.
2851 myText->setElideMode(QQuickText::ElideRight);
2852 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2853 QVERIFY(!myText->truncated());
2854 QCOMPARE(myText->contentWidth(), verticalFitWidth);
2855 QCOMPARE(myText->contentHeight(), verticalFitHeight);
2857 myText->setElideMode(QQuickText::ElideNone);
2858 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2860 myText->setFontSizeMode(QQuickText::Fit);
2861 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2862 // Should be the same as VerticalFit with wrapping.
2863 QCOMPARE(myText->contentWidth(), verticalFitWidth);
2864 QCOMPARE(myText->contentHeight(), verticalFitHeight);
2866 // Elide won't affect the size with Fit.
2867 myText->setElideMode(QQuickText::ElideRight);
2868 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2869 QVERIFY(!myText->truncated());
2870 QCOMPARE(myText->contentWidth(), verticalFitWidth);
2871 QCOMPARE(myText->contentHeight(), verticalFitHeight);
2873 myText->setElideMode(QQuickText::ElideNone);
2874 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2876 myText->setFontSizeMode(QQuickText::FixedSize);
2877 myText->setMaximumLineCount(2);
2878 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2880 // The original text wrapped should exceed the height of the item.
2881 QVERIFY(originalWidth <= myText->width() + 2);
2882 QVERIFY(originalHeight > myText->height());
2884 myText->setFontSizeMode(QQuickText::HorizontalFit);
2885 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2886 // HorizontalFit should reduce the font size to minimize wrapping, which brings it back to the
2887 // same size as without text wrapping.
2888 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2889 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2891 // Elide won't affect the size with HorizontalFit.
2892 myText->setElideMode(QQuickText::ElideRight);
2893 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2894 QVERIFY(!myText->truncated());
2895 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2896 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2898 myText->setElideMode(QQuickText::ElideNone);
2899 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2901 myText->setFontSizeMode(QQuickText::VerticalFit);
2902 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2903 // VerticalFit should reduce the size to the wrapped text within the vertical height.
2904 verticalFitHeight = myText->contentHeight();
2905 verticalFitWidth = myText->contentWidth();
2906 QVERIFY(myText->contentWidth() <= myText->width() + 2);
2907 QVERIFY(verticalFitHeight <= myText->height() + 2);
2908 QVERIFY(verticalFitHeight < originalHeight);
2910 // Elide won't affect the height or width of a wrapped text with VerticalFit.
2911 myText->setElideMode(QQuickText::ElideRight);
2912 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2913 QVERIFY(!myText->truncated());
2914 QCOMPARE(myText->contentWidth(), verticalFitWidth);
2915 QCOMPARE(myText->contentHeight(), verticalFitHeight);
2917 myText->setElideMode(QQuickText::ElideNone);
2918 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2920 myText->setFontSizeMode(QQuickText::Fit);
2921 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2922 // Should be the same as VerticalFit with wrapping.
2923 QCOMPARE(myText->contentWidth(), verticalFitWidth);
2924 QCOMPARE(myText->contentHeight(), verticalFitHeight);
2926 // Elide won't affect the size with Fit.
2927 myText->setElideMode(QQuickText::ElideRight);
2928 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2929 QVERIFY(!myText->truncated());
2930 QCOMPARE(myText->contentWidth(), verticalFitWidth);
2931 QCOMPARE(myText->contentHeight(), verticalFitHeight);
2933 myText->setElideMode(QQuickText::ElideNone);
2934 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2937 void tst_qquicktext::fontSizeModeMultiline_data()
2939 QTest::addColumn<QString>("text");
2940 QTest::newRow("plain") << "The quick red fox jumped\n over the lazy brown dog";
2941 QTest::newRow("styledtext") << "<b>The quick red fox jumped<br/> over the lazy brown dog</b>";
2944 void tst_qquicktext::fontSizeModeMultiline()
2946 QFETCH(QString, text);
2948 QScopedPointer<QQuickView> canvas(createView(testFile("fontSizeMode.qml")));
2951 QQuickText *myText = canvas->rootObject()->findChild<QQuickText*>("myText");
2952 QVERIFY(myText != 0);
2954 myText->setText(text);
2955 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2957 qreal originalWidth = myText->contentWidth();
2958 qreal originalHeight = myText->contentHeight();
2959 QCOMPARE(myText->lineCount(), 2);
2961 // The original text unwrapped should exceed the width and height of the item.
2962 QVERIFY(originalWidth > myText->width());
2963 QVERIFY(originalHeight > myText->height());
2965 QFont font = myText->font();
2966 font.setPixelSize(64);
2968 myText->setFont(font);
2969 myText->setFontSizeMode(QQuickText::HorizontalFit);
2970 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2971 // Font size reduced to fit within the width of the item.
2972 QCOMPARE(myText->lineCount(), 2);
2973 qreal horizontalFitWidth = myText->contentWidth();
2974 qreal horizontalFitHeight = myText->contentHeight();
2975 QVERIFY(horizontalFitWidth <= myText->width() + 2); // rounding
2976 QVERIFY(horizontalFitHeight > myText->height());
2978 // Right eliding will remove the last line
2979 myText->setElideMode(QQuickText::ElideRight);
2980 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2981 QVERIFY(myText->truncated());
2982 QCOMPARE(myText->lineCount(), 1);
2983 QVERIFY(myText->contentWidth() <= myText->width() + 2);
2984 QVERIFY(myText->contentHeight() <= myText->height() + 2);
2986 // Left or middle eliding wont have any effect.
2987 myText->setElideMode(QQuickText::ElideLeft);
2988 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2989 QVERIFY(!myText->truncated());
2990 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2991 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2993 myText->setElideMode(QQuickText::ElideMiddle);
2994 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2995 QVERIFY(!myText->truncated());
2996 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2997 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2999 myText->setElideMode(QQuickText::ElideNone);
3000 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3002 myText->setFontSizeMode(QQuickText::VerticalFit);
3003 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3004 // Font size reduced to fit within the height of the item.
3005 qreal verticalFitWidth = myText->contentWidth();
3006 qreal verticalFitHeight = myText->contentHeight();
3007 QVERIFY(verticalFitWidth <= myText->width() + 2);
3008 QVERIFY(verticalFitHeight <= myText->height() + 2);
3010 // Elide will have no effect.
3011 myText->setElideMode(QQuickText::ElideRight);
3012 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3013 QVERIFY(!myText->truncated());
3014 QVERIFY(myText->contentWidth() <= myText->width() + 2);
3015 QCOMPARE(myText->contentWidth(), verticalFitWidth);
3016 QCOMPARE(myText->contentHeight(), verticalFitHeight);
3018 myText->setElideMode(QQuickText::ElideLeft);
3019 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3020 QVERIFY(!myText->truncated());
3021 QCOMPARE(myText->contentWidth(), verticalFitWidth);
3022 QCOMPARE(myText->contentHeight(), verticalFitHeight);
3024 myText->setElideMode(QQuickText::ElideMiddle);
3025 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3026 QVERIFY(!myText->truncated());
3027 QCOMPARE(myText->contentWidth(), verticalFitWidth);
3028 QCOMPARE(myText->contentHeight(), verticalFitHeight);
3030 myText->setElideMode(QQuickText::ElideNone);
3031 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3033 myText->setFontSizeMode(QQuickText::Fit);
3034 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3035 // Should be the same as VerticalFit with no wrapping.
3036 QCOMPARE(myText->contentWidth(), verticalFitWidth);
3037 QCOMPARE(myText->contentHeight(), verticalFitHeight);
3039 // Elide won't affect the size with Fit.
3040 myText->setElideMode(QQuickText::ElideRight);
3041 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3042 QVERIFY(!myText->truncated());
3043 QCOMPARE(myText->contentWidth(), verticalFitWidth);
3044 QCOMPARE(myText->contentHeight(), verticalFitHeight);
3046 myText->setElideMode(QQuickText::ElideLeft);
3047 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3048 QVERIFY(!myText->truncated());
3049 QCOMPARE(myText->contentWidth(), verticalFitWidth);
3050 QCOMPARE(myText->contentHeight(), verticalFitHeight);
3052 myText->setElideMode(QQuickText::ElideMiddle);
3053 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3054 QVERIFY(!myText->truncated());
3055 QCOMPARE(myText->contentWidth(), verticalFitWidth);
3056 QCOMPARE(myText->contentHeight(), verticalFitHeight);
3058 myText->setElideMode(QQuickText::ElideNone);
3059 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3061 myText->setFontSizeMode(QQuickText::FixedSize);
3062 myText->setWrapMode(QQuickText::Wrap);
3063 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3065 originalWidth = myText->contentWidth();
3066 originalHeight = myText->contentHeight();
3068 // The original text wrapped should exceed the height of the item.
3069 QVERIFY(originalWidth <= myText->width() + 2);
3070 QVERIFY(originalHeight > myText->height());
3072 myText->setFontSizeMode(QQuickText::HorizontalFit);
3073 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3074 // HorizontalFit should reduce the font size to minimize wrapping, which brings it back to the
3075 // same size as without text wrapping.
3076 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
3077 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
3079 // Text will be elided vertically with HorizontalFit
3080 myText->setElideMode(QQuickText::ElideRight);
3081 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3082 QVERIFY(myText->truncated());
3083 QVERIFY(myText->contentWidth() <= myText->width() + 2);
3084 QVERIFY(myText->contentHeight() <= myText->height() + 2);
3086 myText->setElideMode(QQuickText::ElideNone);
3087 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3089 myText->setFontSizeMode(QQuickText::VerticalFit);
3090 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3091 // VerticalFit should reduce the size to the wrapped text within the vertical height.
3092 verticalFitHeight = myText->contentHeight();
3093 verticalFitWidth = myText->contentWidth();
3094 QVERIFY(myText->contentWidth() <= myText->width() + 2);
3095 QVERIFY(verticalFitHeight <= myText->height() + 2);
3096 QVERIFY(verticalFitHeight < originalHeight);
3098 // Elide won't affect the height or width of a wrapped text with VerticalFit.
3099 myText->setElideMode(QQuickText::ElideRight);
3100 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3101 QVERIFY(!myText->truncated());
3102 QCOMPARE(myText->contentWidth(), verticalFitWidth);
3103 QCOMPARE(myText->contentHeight(), verticalFitHeight);
3105 myText->setElideMode(QQuickText::ElideNone);
3106 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3108 myText->setFontSizeMode(QQuickText::Fit);
3109 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3110 // Should be the same as VerticalFit with wrapping.
3111 QCOMPARE(myText->contentWidth(), verticalFitWidth);
3112 QCOMPARE(myText->contentHeight(), verticalFitHeight);
3114 // Elide won't affect the size with Fit.
3115 myText->setElideMode(QQuickText::ElideRight);
3116 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3117 QVERIFY(!myText->truncated());
3118 QCOMPARE(myText->contentWidth(), verticalFitWidth);
3119 QCOMPARE(myText->contentHeight(), verticalFitHeight);
3121 myText->setElideMode(QQuickText::ElideNone);
3122 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3124 myText->setFontSizeMode(QQuickText::FixedSize);
3125 myText->setMaximumLineCount(2);
3126 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3128 // The original text wrapped should exceed the height of the item.
3129 QVERIFY(originalWidth <= myText->width() + 2);
3130 QVERIFY(originalHeight > myText->height());
3132 myText->setFontSizeMode(QQuickText::HorizontalFit);
3133 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3134 // HorizontalFit should reduce the font size to minimize wrapping, which brings it back to the
3135 // same size as without text wrapping.
3136 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
3137 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
3139 // Elide won't affect the size with HorizontalFit.
3140 myText->setElideMode(QQuickText::ElideRight);
3141 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3142 QVERIFY(myText->truncated());
3143 QVERIFY(myText->contentWidth() <= myText->width() + 2);
3144 QVERIFY(myText->contentHeight() <= myText->height() + 2);
3146 myText->setElideMode(QQuickText::ElideNone);
3147 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3149 myText->setFontSizeMode(QQuickText::VerticalFit);
3150 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3151 // VerticalFit should reduce the size to the wrapped text within the vertical height.
3152 verticalFitHeight = myText->contentHeight();
3153 verticalFitWidth = myText->contentWidth();
3154 QVERIFY(myText->contentWidth() <= myText->width() + 2);
3155 QVERIFY(verticalFitHeight <= myText->height() + 2);
3156 QVERIFY(verticalFitHeight < originalHeight);
3158 // Elide won't affect the height or width of a wrapped text with VerticalFit.
3159 myText->setElideMode(QQuickText::ElideRight);
3160 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3161 QVERIFY(!myText->truncated());
3162 QCOMPARE(myText->contentWidth(), verticalFitWidth);
3163 QCOMPARE(myText->contentHeight(), verticalFitHeight);
3165 myText->setElideMode(QQuickText::ElideNone);
3166 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3168 myText->setFontSizeMode(QQuickText::Fit);
3169 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3170 // Should be the same as VerticalFit with wrapping.
3171 QCOMPARE(myText->contentWidth(), verticalFitWidth);
3172 QCOMPARE(myText->contentHeight(), verticalFitHeight);
3174 // Elide won't affect the size with Fit.
3175 myText->setElideMode(QQuickText::ElideRight);
3176 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3177 QVERIFY(!myText->truncated());
3178 QCOMPARE(myText->contentWidth(), verticalFitWidth);
3179 QCOMPARE(myText->contentHeight(), verticalFitHeight);
3181 myText->setElideMode(QQuickText::ElideNone);
3182 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3185 void tst_qquicktext::multilengthStrings_data()
3187 QTest::addColumn<QString>("source");
3188 QTest::newRow("No Wrap") << testFile("multilengthStrings.qml");
3189 QTest::newRow("Wrap") << testFile("multilengthStringsWrapped.qml");
3192 void tst_qquicktext::multilengthStrings()
3194 QFETCH(QString, source);
3196 QScopedPointer<QQuickView> canvas(createView(source));
3199 QQuickText *myText = canvas->rootObject()->findChild<QQuickText*>("myText");
3200 QVERIFY(myText != 0);
3202 const QString longText = "the quick brown fox jumped over the lazy dog";
3203 const QString mediumText = "the brown fox jumped over the dog";
3204 const QString shortText = "fox jumped dog";
3206 myText->setText(longText);
3207 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3208 const qreal longWidth = myText->contentWidth();
3209 const qreal longHeight = myText->contentHeight();
3211 myText->setText(mediumText);
3212 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3213 const qreal mediumWidth = myText->contentWidth();
3214 const qreal mediumHeight = myText->contentHeight();
3216 myText->setText(shortText);
3217 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3218 const qreal shortWidth = myText->contentWidth();
3219 const qreal shortHeight = myText->contentHeight();
3221 myText->setElideMode(QQuickText::ElideRight);
3222 myText->setText(longText + QLatin1Char('\x9c') + mediumText + QLatin1Char('\x9c') + shortText);
3224 myText->setSize(QSizeF(longWidth, longHeight));
3225 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3227 QCOMPARE(myText->contentWidth(), longWidth);
3228 QCOMPARE(myText->contentHeight(), longHeight);
3229 QCOMPARE(myText->truncated(), false);
3231 myText->setSize(QSizeF(mediumWidth, mediumHeight));
3232 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3234 QCOMPARE(myText->contentWidth(), mediumWidth);
3235 QCOMPARE(myText->contentHeight(), mediumHeight);
3236 QCOMPARE(myText->truncated(), true);
3238 myText->setSize(QSizeF(shortWidth, shortHeight));
3239 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3241 QCOMPARE(myText->contentWidth(), shortWidth);
3242 QCOMPARE(myText->contentHeight(), shortHeight);
3243 QCOMPARE(myText->truncated(), true);
3246 void tst_qquicktext::fontFormatSizes_data()
3248 QTest::addColumn<QString>("text");
3249 QTest::addColumn<QString>("textWithTag");
3250 QTest::addColumn<bool>("fontIsBigger");
3252 QTest::newRow("fs1") << "Hello world!" << "Hello <font size=\"1\">world</font>!" << false;
3253 QTest::newRow("fs2") << "Hello world!" << "Hello <font size=\"2\">world</font>!" << false;
3254 QTest::newRow("fs3") << "Hello world!" << "Hello <font size=\"3\">world</font>!" << false;
3255 QTest::newRow("fs4") << "Hello world!" << "Hello <font size=\"4\">world</font>!" << true;
3256 QTest::newRow("fs5") << "Hello world!" << "Hello <font size=\"5\">world</font>!" << true;
3257 QTest::newRow("fs6") << "Hello world!" << "Hello <font size=\"6\">world</font>!" << true;
3258 QTest::newRow("fs7") << "Hello world!" << "Hello <font size=\"7\">world</font>!" << true;
3259 QTest::newRow("h1") << "This is<br/>a font<br/> size test." << "This is <h1>a font</h1> size test." << true;
3260 QTest::newRow("h2") << "This is<br/>a font<br/> size test." << "This is <h2>a font</h2> size test." << true;
3261 QTest::newRow("h3") << "This is<br/>a font<br/> size test." << "This is <h3>a font</h3> size test." << true;
3262 QTest::newRow("h4") << "This is<br/>a font<br/> size test." << "This is <h4>a font</h4> size test." << true;
3263 QTest::newRow("h5") << "This is<br/>a font<br/> size test." << "This is <h5>a font</h5> size test." << false;
3264 QTest::newRow("h6") << "This is<br/>a font<br/> size test." << "This is <h6>a font</h6> size test." << false;
3267 void tst_qquicktext::fontFormatSizes()
3269 QFETCH(QString, text);
3270 QFETCH(QString, textWithTag);
3271 QFETCH(bool, fontIsBigger);
3273 QQuickView *view = new QQuickView;
3275 view->setSource(testFileUrl("pointFontSizes.qml"));
3278 QQuickText *qtext = view->rootObject()->findChild<QQuickText*>("text");
3279 QQuickText *qtextWithTag = view->rootObject()->findChild<QQuickText*>("textWithTag");
3280 QVERIFY(qtext != 0);
3281 QVERIFY(qtextWithTag != 0);
3283 qtext->setText(text);
3284 qtextWithTag->setText(textWithTag);
3286 for (int size = 6; size < 100; size += 4) {
3287 view->rootObject()->setProperty("pointSize", size);
3289 QVERIFY(qtext->height() <= qtextWithTag->height());
3291 QVERIFY(qtext->height() >= qtextWithTag->height());
3296 view->setSource(testFileUrl("pixelFontSizes.qml"));
3297 QQuickText *qtext = view->rootObject()->findChild<QQuickText*>("text");
3298 QQuickText *qtextWithTag = view->rootObject()->findChild<QQuickText*>("textWithTag");
3299 QVERIFY(qtext != 0);
3300 QVERIFY(qtextWithTag != 0);
3302 qtext->setText(text);
3303 qtextWithTag->setText(textWithTag);
3305 for (int size = 6; size < 100; size += 4) {
3306 view->rootObject()->setProperty("pixelSize", size);
3308 QVERIFY(qtext->height() <= qtextWithTag->height());
3310 QVERIFY(qtext->height() >= qtextWithTag->height());
3316 typedef qreal (*ExpectedBaseline)(QQuickText *item);
3317 Q_DECLARE_METATYPE(ExpectedBaseline)
3319 static qreal expectedBaselineTop(QQuickText *item)
3321 QFontMetricsF fm(item->font());
3325 static qreal expectedBaselineBottom(QQuickText *item)
3327 QFontMetricsF fm(item->font());
3328 return item->height() - item->contentHeight() + fm.ascent();
3331 static qreal expectedBaselineCenter(QQuickText *item)
3333 QFontMetricsF fm(item->font());
3334 return ((item->height() - item->contentHeight()) / 2) + fm.ascent();
3337 static qreal expectedBaselineBold(QQuickText *item)
3339 QFont font = item->font();
3341 QFontMetricsF fm(font);
3345 static qreal expectedBaselineImage(QQuickText *item)
3347 QFontMetricsF fm(item->font());
3348 // The line is positioned so the bottom of the line is aligned with the bottom of the image,
3349 // or image height - line height and the baseline is line position + ascent. Because
3350 // QTextLine's height is rounded up this can give slightly different results to image height
3352 return 181 - qCeil(fm.height()) + fm.ascent();
3355 static qreal expectedBaselineCustom(QQuickText *item)
3357 QFontMetricsF fm(item->font());
3358 return 16 + fm.ascent();
3361 static qreal expectedBaselineScaled(QQuickText *item)
3363 QFont font = item->font();
3364 QTextLayout layout(item->text().replace(QLatin1Char('\n'), QChar::LineSeparator));
3366 layout.setFont(font);
3368 layout.beginLayout();
3369 for (QTextLine line = layout.createLine(); line.isValid(); line = layout.createLine()) {
3370 line.setLineWidth(FLT_MAX);
3371 width = qMax(line.naturalTextWidth(), width);
3375 if (width < item->width()) {
3376 QFontMetricsF fm(layout.font());
3379 font.setPointSize(font.pointSize() - 1);
3380 } while (font.pointSize() > 0);
3384 static qreal expectedBaselineFixedBottom(QQuickText *item)
3386 QFontMetricsF fm(item->font());
3387 qreal dy = item->text().contains(QLatin1Char('\n'))
3390 return dy + fm.ascent();
3393 static qreal expectedBaselineProportionalBottom(QQuickText *item)
3395 QFontMetricsF fm(item->font());
3396 qreal dy = item->text().contains(QLatin1Char('\n'))
3397 ? 200 - (qCeil(fm.height()) * 3)
3398 : 200 - (qCeil(fm.height()) * 1.5);
3399 return dy + fm.ascent();
3402 void tst_qquicktext::baselineOffset_data()
3404 qRegisterMetaType<ExpectedBaseline>();
3405 QTest::addColumn<QString>("text");
3406 QTest::addColumn<QString>("wrappedText");
3407 QTest::addColumn<QByteArray>("bindings");
3408 QTest::addColumn<ExpectedBaseline>("expectedBaseline");
3409 QTest::addColumn<ExpectedBaseline>("expectedBaselineEmpty");
3411 QTest::newRow("top align")
3414 << QByteArray("height: 200; verticalAlignment: Text.AlignTop")
3415 << &expectedBaselineTop
3416 << &expectedBaselineTop;
3417 QTest::newRow("bottom align")
3420 << QByteArray("height: 200; verticalAlignment: Text.AlignBottom")
3421 << &expectedBaselineBottom
3422 << &expectedBaselineBottom;
3423 QTest::newRow("center align")
3426 << QByteArray("height: 200; verticalAlignment: Text.AlignVCenter")
3427 << &expectedBaselineCenter
3428 << &expectedBaselineCenter;
3430 QTest::newRow("bold")
3431 << "<b>hello world</b>"
3432 << "<b>hello<br/>world</b>"
3433 << QByteArray("height: 200")
3434 << &expectedBaselineTop
3435 << &expectedBaselineBold;
3437 QTest::newRow("richText")
3438 << "<b>hello world</b>"
3439 << "<b>hello<br/>world</b>"
3440 << QByteArray("height: 200; textFormat: Text.RichText")
3441 << &expectedBaselineTop
3442 << &expectedBaselineTop;
3444 QTest::newRow("elided")
3447 << QByteArray("width: 20; height: 8; elide: Text.ElideRight")
3448 << &expectedBaselineTop
3449 << &expectedBaselineTop;
3451 QTest::newRow("elided bottom align")
3453 << "hello\nworld!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
3454 << QByteArray("width: 200; height: 200; elide: Text.ElideRight; verticalAlignment: Text.AlignBottom")
3455 << &expectedBaselineBottom
3456 << &expectedBaselineBottom;
3458 QTest::newRow("image")
3459 << "hello <img src=\"images/heart200.png\" /> world"
3460 << "hello <img src=\"images/heart200.png\" /><br/>world"
3461 << QByteArray("height: 200\n; baseUrl: \"") + testFileUrl("reference").toEncoded() + QByteArray("\"")
3462 << &expectedBaselineImage
3463 << &expectedBaselineTop;
3465 QTest::newRow("customLine")
3468 << QByteArray("height: 200; onLineLaidOut: line.y += 16")
3469 << &expectedBaselineCustom
3470 << &expectedBaselineCustom;
3472 QTest::newRow("scaled font")
3475 << QByteArray("width: 200; minimumPointSize: 1; font.pointSize: 64; fontSizeMode: Text.HorizontalFit")
3476 << &expectedBaselineScaled
3477 << &expectedBaselineTop;
3479 QTest::newRow("fixed line height top align")
3482 << QByteArray("height: 200; lineHeightMode: Text.FixedHeight; lineHeight: 20; verticalAlignment: Text.AlignTop")
3483 << &expectedBaselineTop
3484 << &expectedBaselineTop;
3486 QTest::newRow("fixed line height bottom align")
3489 << QByteArray("height: 200; lineHeightMode: Text.FixedHeight; lineHeight: 20; verticalAlignment: Text.AlignBottom")
3490 << &expectedBaselineFixedBottom
3491 << &expectedBaselineFixedBottom;
3493 QTest::newRow("proportional line height top align")
3496 << QByteArray("height: 200; lineHeightMode: Text.ProportionalHeight; lineHeight: 1.5; verticalAlignment: Text.AlignTop")
3497 << &expectedBaselineTop
3498 << &expectedBaselineTop;
3500 QTest::newRow("proportional line height bottom align")
3503 << QByteArray("height: 200; lineHeightMode: Text.ProportionalHeight; lineHeight: 1.5; verticalAlignment: Text.AlignBottom")
3504 << &expectedBaselineProportionalBottom
3505 << &expectedBaselineProportionalBottom;
3508 void tst_qquicktext::baselineOffset()
3510 QFETCH(QString, text);
3511 QFETCH(QString, wrappedText);
3512 QFETCH(QByteArray, bindings);
3513 QFETCH(ExpectedBaseline, expectedBaseline);
3514 QFETCH(ExpectedBaseline, expectedBaselineEmpty);
3516 QQmlComponent component(&engine);
3518 "import QtQuick 2.0\n"
3523 QScopedPointer<QObject> object(component.create());
3525 QQuickText *item = qobject_cast<QQuickText *>(object.data());
3529 qreal baseline = expectedBaselineEmpty(item);
3531 QCOMPARE(item->baselineOffset(), baseline);
3533 item->setText(text);
3534 if (expectedBaseline != expectedBaselineEmpty)
3535 baseline = expectedBaseline(item);
3537 QCOMPARE(item->baselineOffset(), baseline);
3539 item->setText(wrappedText);
3540 QCOMPARE(item->baselineOffset(), expectedBaseline(item));
3543 QFont font = item->font();
3544 font.setPointSize(font.pointSize() + 8);
3547 QCOMPARE(item->baselineOffset(), expectedBaseline(item));
3549 item->setText(text);
3550 qreal baseline = expectedBaseline(item);
3551 QCOMPARE(item->baselineOffset(), baseline);
3553 item->setText(QString());
3554 if (expectedBaselineEmpty != expectedBaseline)
3555 baseline = expectedBaselineEmpty(item);
3557 QCOMPARE(item->baselineOffset(), baseline);
3561 void tst_qquicktext::htmlLists()
3563 QFETCH(QString, text);
3564 QFETCH(int, nbLines);
3566 QQuickView *view = createView(testFile("htmlLists.qml"));
3567 QQuickText *textObject = view->rootObject()->findChild<QQuickText*>("myText");
3569 QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject);
3570 QVERIFY(textPrivate != 0);
3571 QVERIFY(textPrivate->extra.isAllocated());
3573 QVERIFY(textObject != 0);
3574 textObject->setText(text);
3577 view->requestActivateWindow();
3578 QTest::qWaitForWindowShown(view);
3580 QCOMPARE(textPrivate->extra->doc->lineCount(), nbLines);
3585 void tst_qquicktext::htmlLists_data()
3587 QTest::addColumn<QString>("text");
3588 QTest::addColumn<int>("nbLines");
3590 QTest::newRow("ordered list") << "<ol><li>one<li>two<li>three" << 3;
3591 QTest::newRow("ordered list closed") << "<ol><li>one</li></ol>" << 1;
3592 QTest::newRow("ordered list alpha") << "<ol type=\"a\"><li>one</li><li>two</li></ol>" << 2;
3593 QTest::newRow("ordered list upper alpha") << "<ol type=\"A\"><li>one</li><li>two</li></ol>" << 2;
3594 QTest::newRow("ordered list roman") << "<ol type=\"i\"><li>one</li><li>two</li></ol>" << 2;
3595 QTest::newRow("ordered list upper roman") << "<ol type=\"I\"><li>one</li><li>two</li></ol>" << 2;
3596 QTest::newRow("ordered list bad") << "<ol type=\"z\"><li>one</li><li>two</li></ol>" << 2;
3597 QTest::newRow("unordered list") << "<ul><li>one<li>two" << 2;
3598 QTest::newRow("unordered list closed") << "<ul><li>one</li><li>two</li></ul>" << 2;
3599 QTest::newRow("unordered list disc") << "<ul type=\"disc\"><li>one</li><li>two</li></ul>" << 2;
3600 QTest::newRow("unordered list square") << "<ul type=\"square\"><li>one</li><li>two</li></ul>" << 2;
3601 QTest::newRow("unordered list bad") << "<ul type=\"bad\"><li>one</li><li>two</li></ul>" << 2;
3604 QTEST_MAIN(tst_qquicktext)
3606 #include "tst_qquicktext.moc"