1 /****************************************************************************
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
6 ** This file is part of the test suite of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
40 ****************************************************************************/
42 #include <QtTest/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();
87 void embeddedImages_data();
88 void embeddedImages();
93 // ### these tests may be trivial
94 void horizontalAlignment();
95 void horizontalAlignment_RightToLeft();
96 void verticalAlignment();
97 void hAlignImplicitWidth();
104 // QQuickFontValueType
109 void capitalization();
110 void letterSpacing();
113 void clickLink_data();
116 void implicitSize_data();
119 void implicitSizeBinding_data();
120 void implicitSizeBinding();
121 void geometryChanged();
123 void boundingRect_data();
127 void lineLaidOutRelayout();
129 void imgTagsBaseUrl_data();
130 void imgTagsBaseUrl();
131 void imgTagsAlign_data();
133 void imgTagsMultipleImages();
135 void imgTagsUpdates();
137 void fontSizeMode_data();
139 void fontSizeModeMultiline_data();
140 void fontSizeModeMultiline();
141 void multilengthStrings_data();
142 void multilengthStrings();
143 void fontFormatSizes_data();
144 void fontFormatSizes();
146 void baselineOffset_data();
147 void baselineOffset();
150 void htmlLists_data();
153 QStringList standard;
154 QStringList richText;
156 QStringList horizontalAlignmentmentStrings;
157 QStringList verticalAlignmentmentStrings;
159 QList<Qt::Alignment> verticalAlignmentments;
160 QList<Qt::Alignment> horizontalAlignmentments;
162 QStringList styleStrings;
163 QList<QQuickText::TextStyle> styles;
165 QStringList colorStrings;
169 QQuickView *createView(const QString &filename);
170 int numberOfNonWhitePixels(int fromX, int toX, const QImage &image);
173 tst_qquicktext::tst_qquicktext()
175 standard << "the quick brown fox jumped over the lazy dog"
176 << "the quick brown fox\n jumped over the lazy dog";
178 richText << "<i>the <b>quick</b> brown <a href=\\\"http://www.google.com\\\">fox</a> jumped over the <b>lazy</b> dog</i>"
179 << "<i>the <b>quick</b> brown <a href=\\\"http://www.google.com\\\">fox</a><br>jumped over the <b>lazy</b> dog</i>";
181 horizontalAlignmentmentStrings << "AlignLeft"
185 verticalAlignmentmentStrings << "AlignTop"
189 horizontalAlignmentments << Qt::AlignLeft
193 verticalAlignmentments << Qt::AlignTop
197 styleStrings << "Normal"
202 styles << QQuickText::Normal
203 << QQuickText::Outline
204 << QQuickText::Raised
205 << QQuickText::Sunken;
207 colorStrings << "aliceblue"
220 // need a different test to do alpha channel test
224 qt_setQtEnableTestFont(true);
227 QQuickView *tst_qquicktext::createView(const QString &filename)
229 QQuickView *window = new QQuickView(0);
231 window->setSource(QUrl::fromLocalFile(filename));
235 void tst_qquicktext::text()
238 QQmlComponent textComponent(&engine);
239 textComponent.setData("import QtQuick 2.0\nText { text: \"\" }", QUrl::fromLocalFile(""));
240 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
242 QVERIFY(textObject != 0);
243 QCOMPARE(textObject->text(), QString(""));
244 QVERIFY(textObject->width() == 0);
249 for (int i = 0; i < standard.size(); i++)
251 QString componentStr = "import QtQuick 2.0\nText { text: \"" + standard.at(i) + "\" }";
252 QQmlComponent textComponent(&engine);
253 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
255 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
257 QVERIFY(textObject != 0);
258 QCOMPARE(textObject->text(), standard.at(i));
259 QVERIFY(textObject->width() > 0);
264 for (int i = 0; i < richText.size(); i++)
266 QString componentStr = "import QtQuick 2.0\nText { text: \"" + richText.at(i) + "\" }";
267 QQmlComponent textComponent(&engine);
268 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
269 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
271 QVERIFY(textObject != 0);
272 QString expected = richText.at(i);
273 QCOMPARE(textObject->text(), expected.replace("\\\"", "\""));
274 QVERIFY(textObject->width() > 0);
280 void tst_qquicktext::width()
282 // uses Font metrics to find the width for standard and document to find the width for rich
284 QQmlComponent textComponent(&engine);
285 textComponent.setData("import QtQuick 2.0\nText { text: \"\" }", QUrl::fromLocalFile(""));
286 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
288 QVERIFY(textObject != 0);
289 QCOMPARE(textObject->width(), 0.);
294 bool requiresUnhintedMetrics = !qmlDisableDistanceField();
296 for (int i = 0; i < standard.size(); i++)
298 QVERIFY(!Qt::mightBeRichText(standard.at(i))); // self-test
301 qreal metricWidth = 0.0;
303 if (requiresUnhintedMetrics) {
304 QString s = standard.at(i);
305 s.replace(QLatin1Char('\n'), QChar::LineSeparator);
307 QTextLayout layout(s);
308 layout.setFlags(Qt::TextExpandTabs | Qt::TextShowMnemonic);
311 option.setUseDesignMetrics(true);
312 layout.setTextOption(option);
315 layout.beginLayout();
317 QTextLine line = layout.createLine();
324 metricWidth = layout.boundingRect().width();
327 metricWidth = fm.size(Qt::TextExpandTabs && Qt::TextShowMnemonic, standard.at(i)).width();
330 QString componentStr = "import QtQuick 2.0\nText { text: \"" + standard.at(i) + "\" }";
331 QQmlComponent textComponent(&engine);
332 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
333 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
335 QVERIFY(textObject != 0);
336 QVERIFY(textObject->boundingRect().width() > 0);
337 QCOMPARE(textObject->width(), qreal(metricWidth));
338 QVERIFY(textObject->textFormat() == QQuickText::AutoText); // setting text doesn't change format
343 for (int i = 0; i < richText.size(); i++)
345 QVERIFY(Qt::mightBeRichText(richText.at(i))); // self-test
347 QString componentStr = "import QtQuick 2.0\nText { text: \"" + richText.at(i) + "\"; textFormat: Text.RichText }";
348 QQmlComponent textComponent(&engine);
349 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
350 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
351 QVERIFY(textObject != 0);
353 QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject);
354 QVERIFY(textPrivate != 0);
355 QVERIFY(textPrivate->extra.isAllocated());
357 QTextDocument *doc = textPrivate->extra->doc;
360 QCOMPARE(int(textObject->width()), int(doc->idealWidth()));
361 QVERIFY(textObject->textFormat() == QQuickText::RichText);
367 void tst_qquicktext::wrap()
370 // for specified width and wrap set true
372 QQmlComponent textComponent(&engine);
373 textComponent.setData("import QtQuick 2.0\nText { text: \"Hello\"; wrapMode: Text.WordWrap; width: 300 }", QUrl::fromLocalFile(""));
374 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
375 textHeight = textObject->height();
377 QVERIFY(textObject != 0);
378 QVERIFY(textObject->wrapMode() == QQuickText::WordWrap);
379 QCOMPARE(textObject->width(), 300.);
384 for (int i = 0; i < standard.size(); i++)
386 QString componentStr = "import QtQuick 2.0\nText { wrapMode: Text.WordWrap; width: 30; text: \"" + standard.at(i) + "\" }";
387 QQmlComponent textComponent(&engine);
388 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
389 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
391 QVERIFY(textObject != 0);
392 QCOMPARE(textObject->width(), 30.);
393 QVERIFY(textObject->height() > textHeight);
395 int oldHeight = textObject->height();
396 textObject->setWidth(100);
397 QVERIFY(textObject->height() < oldHeight);
402 for (int i = 0; i < richText.size(); i++)
404 QString componentStr = "import QtQuick 2.0\nText { wrapMode: Text.WordWrap; width: 30; text: \"" + richText.at(i) + "\" }";
405 QQmlComponent textComponent(&engine);
406 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
407 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
409 QVERIFY(textObject != 0);
410 QCOMPARE(textObject->width(), 30.);
411 QVERIFY(textObject->height() > textHeight);
413 qreal oldHeight = textObject->height();
414 textObject->setWidth(100);
415 QVERIFY(textObject->height() < oldHeight);
420 // richtext again with a fixed height
421 for (int i = 0; i < richText.size(); i++)
423 QString componentStr = "import QtQuick 2.0\nText { wrapMode: Text.WordWrap; width: 30; height: 50; text: \"" + richText.at(i) + "\" }";
424 QQmlComponent textComponent(&engine);
425 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
426 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
428 QVERIFY(textObject != 0);
429 QCOMPARE(textObject->width(), 30.);
430 QVERIFY(textObject->implicitHeight() > textHeight);
432 qreal oldHeight = textObject->implicitHeight();
433 textObject->setWidth(100);
434 QVERIFY(textObject->implicitHeight() < oldHeight);
440 QQmlComponent component(&engine);
441 component.setData("import QtQuick 2.0\n Text {}", QUrl());
442 QScopedPointer<QObject> object(component.create());
443 QQuickText *textObject = qobject_cast<QQuickText *>(object.data());
446 QSignalSpy spy(textObject, SIGNAL(wrapModeChanged()));
448 QCOMPARE(textObject->wrapMode(), QQuickText::NoWrap);
450 textObject->setWrapMode(QQuickText::Wrap);
451 QCOMPARE(textObject->wrapMode(), QQuickText::Wrap);
452 QCOMPARE(spy.count(), 1);
454 textObject->setWrapMode(QQuickText::Wrap);
455 QCOMPARE(spy.count(), 1);
457 textObject->setWrapMode(QQuickText::NoWrap);
458 QCOMPARE(textObject->wrapMode(), QQuickText::NoWrap);
459 QCOMPARE(spy.count(), 2);
463 void tst_qquicktext::elide()
465 for (QQuickText::TextElideMode m = QQuickText::ElideLeft; m<=QQuickText::ElideNone; m=QQuickText::TextElideMode(int(m)+1)) {
466 const char* elidename[]={"ElideLeft", "ElideRight", "ElideMiddle", "ElideNone"};
467 QString elide = "elide: Text." + QString(elidename[int(m)]) + ";";
469 // XXX Poor coverage.
472 QQmlComponent textComponent(&engine);
473 textComponent.setData(("import QtQuick 2.0\nText { text: \"\"; "+elide+" width: 100 }").toLatin1(), QUrl::fromLocalFile(""));
474 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
476 QCOMPARE(textObject->elideMode(), m);
477 QCOMPARE(textObject->width(), 100.);
482 for (int i = 0; i < standard.size(); i++)
484 QString componentStr = "import QtQuick 2.0\nText { "+elide+" width: 100; text: \"" + standard.at(i) + "\" }";
485 QQmlComponent textComponent(&engine);
486 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
487 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
489 QCOMPARE(textObject->elideMode(), m);
490 QCOMPARE(textObject->width(), 100.);
492 if (m != QQuickText::ElideNone && !standard.at(i).contains('\n'))
493 QVERIFY(textObject->contentWidth() <= textObject->width());
498 for (int i = 0; i < richText.size(); i++)
500 QString componentStr = "import QtQuick 2.0\nText { "+elide+" width: 100; text: \"" + richText.at(i) + "\" }";
501 QQmlComponent textComponent(&engine);
502 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
503 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
505 QCOMPARE(textObject->elideMode(), m);
506 QCOMPARE(textObject->width(), 100.);
508 if (m != QQuickText::ElideNone && standard.at(i).contains("<br>"))
509 QVERIFY(textObject->contentWidth() <= textObject->width());
516 void tst_qquicktext::multilineElide_data()
518 QTest::addColumn<QQuickText::TextFormat>("format");
519 QTest::newRow("plain") << QQuickText::PlainText;
520 QTest::newRow("styled") << QQuickText::StyledText;
523 void tst_qquicktext::multilineElide()
525 QFETCH(QQuickText::TextFormat, format);
526 QQuickView *window = createView(testFile("multilineelide.qml"));
528 QQuickText *myText = qobject_cast<QQuickText*>(window->rootObject());
529 QVERIFY(myText != 0);
530 myText->setTextFormat(format);
532 QCOMPARE(myText->lineCount(), 3);
533 QCOMPARE(myText->truncated(), true);
535 qreal lineHeight = myText->contentHeight() / 3.;
537 // Set a valid height greater than the truncated content height and ensure the line count is
539 myText->setHeight(200);
540 QCOMPARE(myText->lineCount(), 3);
541 QCOMPARE(myText->truncated(), true);
543 // reduce size and ensure fewer lines are drawn
544 myText->setHeight(lineHeight * 2);
545 QCOMPARE(myText->lineCount(), 2);
547 myText->setHeight(lineHeight);
548 QCOMPARE(myText->lineCount(), 1);
550 myText->setHeight(5);
551 QCOMPARE(myText->lineCount(), 1);
553 myText->setHeight(lineHeight * 3);
554 QCOMPARE(myText->lineCount(), 3);
556 // remove max count and show all lines.
557 myText->setHeight(1000);
558 myText->resetMaximumLineCount();
560 QCOMPARE(myText->truncated(), false);
563 myText->setHeight(lineHeight * 2);
564 QCOMPARE(myText->lineCount(), 2);
565 QCOMPARE(myText->truncated(), true);
567 // change line height
568 myText->setLineHeight(1.1);
569 QCOMPARE(myText->lineCount(), 1);
574 void tst_qquicktext::implicitElide_data()
576 QTest::addColumn<QString>("width");
577 QTest::addColumn<QString>("initialText");
578 QTest::addColumn<QString>("text");
580 QTest::newRow("maximum width, empty")
581 << "Math.min(implicitWidth, 100)"
583 QTest::newRow("maximum width, short")
584 << "Math.min(implicitWidth, 100)"
586 QTest::newRow("maximum width, long")
587 << "Math.min(implicitWidth, 100)"
588 << "the quick brown fox jumped over the lazy dog";
589 QTest::newRow("reset width, empty")
590 << "implicitWidth > 100 ? 100 : undefined"
592 QTest::newRow("reset width, short")
593 << "implicitWidth > 100 ? 100 : undefined"
595 QTest::newRow("reset width, long")
596 << "implicitWidth > 100 ? 100 : undefined"
597 << "the quick brown fox jumped over the lazy dog";
600 void tst_qquicktext::implicitElide()
602 QFETCH(QString, width);
603 QFETCH(QString, initialText);
605 QString componentStr =
606 "import QtQuick 2.0\n"
608 "width: " + width + "\n"
609 "text: \"" + initialText + "\"\n"
610 "elide: Text.ElideRight\n"
612 QQmlComponent textComponent(&engine);
613 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
614 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
616 QVERIFY(textObject->contentWidth() <= textObject->width());
618 textObject->setText("the quick brown fox jumped over");
620 QVERIFY(textObject->contentWidth() > 0);
621 QVERIFY(textObject->contentWidth() <= textObject->width());
624 void tst_qquicktext::textFormat()
627 QQmlComponent textComponent(&engine);
628 textComponent.setData("import QtQuick 2.0\nText { text: \"Hello\"; textFormat: Text.RichText }", QUrl::fromLocalFile(""));
629 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
631 QVERIFY(textObject != 0);
632 QVERIFY(textObject->textFormat() == QQuickText::RichText);
634 QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject);
635 QVERIFY(textPrivate != 0);
636 QVERIFY(textPrivate->richText == true);
641 QQmlComponent textComponent(&engine);
642 textComponent.setData("import QtQuick 2.0\nText { text: \"<b>Hello</b>\" }", QUrl::fromLocalFile(""));
643 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
645 QVERIFY(textObject != 0);
646 QVERIFY(textObject->textFormat() == QQuickText::AutoText);
648 QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject);
649 QVERIFY(textPrivate != 0);
650 QVERIFY(textPrivate->styledText == true);
655 QQmlComponent textComponent(&engine);
656 textComponent.setData("import QtQuick 2.0\nText { text: \"<b>Hello</b>\"; textFormat: Text.PlainText }", QUrl::fromLocalFile(""));
657 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
659 QVERIFY(textObject != 0);
660 QVERIFY(textObject->textFormat() == QQuickText::PlainText);
666 QQmlComponent component(&engine);
667 component.setData("import QtQuick 2.0\n Text {}", QUrl());
668 QScopedPointer<QObject> object(component.create());
669 QQuickText *text = qobject_cast<QQuickText *>(object.data());
672 QSignalSpy spy(text, SIGNAL(textFormatChanged(TextFormat)));
674 QCOMPARE(text->textFormat(), QQuickText::AutoText);
676 text->setTextFormat(QQuickText::StyledText);
677 QCOMPARE(text->textFormat(), QQuickText::StyledText);
678 QCOMPARE(spy.count(), 1);
680 text->setTextFormat(QQuickText::StyledText);
681 QCOMPARE(spy.count(), 1);
683 text->setTextFormat(QQuickText::AutoText);
684 QCOMPARE(text->textFormat(), QQuickText::AutoText);
685 QCOMPARE(spy.count(), 2);
689 //the alignment tests may be trivial o.oa
690 void tst_qquicktext::horizontalAlignment()
692 //test one align each, and then test if two align fails.
694 for (int i = 0; i < standard.size(); i++)
696 for (int j=0; j < horizontalAlignmentmentStrings.size(); j++)
698 QString componentStr = "import QtQuick 2.0\nText { horizontalAlignment: \"" + horizontalAlignmentmentStrings.at(j) + "\"; text: \"" + standard.at(i) + "\" }";
699 QQmlComponent textComponent(&engine);
700 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
701 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
703 QCOMPARE((int)textObject->hAlign(), (int)horizontalAlignmentments.at(j));
709 for (int i = 0; i < richText.size(); i++)
711 for (int j=0; j < horizontalAlignmentmentStrings.size(); j++)
713 QString componentStr = "import QtQuick 2.0\nText { horizontalAlignment: \"" + horizontalAlignmentmentStrings.at(j) + "\"; text: \"" + richText.at(i) + "\" }";
714 QQmlComponent textComponent(&engine);
715 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
716 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
718 QCOMPARE((int)textObject->hAlign(), (int)horizontalAlignmentments.at(j));
726 void tst_qquicktext::horizontalAlignment_RightToLeft()
728 QQuickView *window = createView(testFile("horizontalAlignment_RightToLeft.qml"));
729 QQuickText *text = window->rootObject()->findChild<QQuickText*>("text");
733 QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(text);
734 QVERIFY(textPrivate != 0);
736 QTRY_VERIFY(textPrivate->layout.lineCount());
738 // implicit alignment should follow the reading direction of RTL text
739 QCOMPARE(text->hAlign(), QQuickText::AlignRight);
740 QCOMPARE(text->effectiveHAlign(), text->hAlign());
741 QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > window->width()/2);
743 // explicitly left aligned text
744 text->setHAlign(QQuickText::AlignLeft);
745 QCOMPARE(text->hAlign(), QQuickText::AlignLeft);
746 QCOMPARE(text->effectiveHAlign(), text->hAlign());
747 QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() < window->width()/2);
749 // explicitly right aligned text
750 text->setHAlign(QQuickText::AlignRight);
751 QCOMPARE(text->hAlign(), QQuickText::AlignRight);
752 QCOMPARE(text->effectiveHAlign(), text->hAlign());
753 QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > window->width()/2);
755 // change to rich text
756 QString textString = text->text();
757 text->setText(QString("<i>") + textString + QString("</i>"));
758 text->setTextFormat(QQuickText::RichText);
761 // implicitly aligned rich text should follow the reading direction of text
762 QCOMPARE(text->hAlign(), QQuickText::AlignRight);
763 QCOMPARE(text->effectiveHAlign(), text->hAlign());
764 QVERIFY(textPrivate->extra.isAllocated());
765 QVERIFY(textPrivate->extra->doc->defaultTextOption().alignment() & Qt::AlignLeft);
767 // explicitly left aligned rich text
768 text->setHAlign(QQuickText::AlignLeft);
769 QCOMPARE(text->hAlign(), QQuickText::AlignLeft);
770 QCOMPARE(text->effectiveHAlign(), text->hAlign());
771 QVERIFY(textPrivate->extra->doc->defaultTextOption().alignment() & Qt::AlignRight);
773 // explicitly right aligned rich text
774 text->setHAlign(QQuickText::AlignRight);
775 QCOMPARE(text->hAlign(), QQuickText::AlignRight);
776 QCOMPARE(text->effectiveHAlign(), text->hAlign());
777 QVERIFY(textPrivate->extra->doc->defaultTextOption().alignment() & Qt::AlignLeft);
779 text->setText(textString);
780 text->setTextFormat(QQuickText::PlainText);
782 // explicitly center aligned
783 text->setHAlign(QQuickText::AlignHCenter);
784 QCOMPARE(text->hAlign(), QQuickText::AlignHCenter);
785 QCOMPARE(text->effectiveHAlign(), text->hAlign());
786 QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() < window->width()/2);
787 QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().right() > window->width()/2);
789 // reseted alignment should go back to following the text reading direction
791 QCOMPARE(text->hAlign(), QQuickText::AlignRight);
792 QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > window->width()/2);
794 // mirror the text item
795 QQuickItemPrivate::get(text)->setLayoutMirror(true);
797 // mirrored implicit alignment should continue to follow the reading direction of the text
798 QCOMPARE(text->hAlign(), QQuickText::AlignRight);
799 QCOMPARE(text->effectiveHAlign(), QQuickText::AlignRight);
800 QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > window->width()/2);
802 // mirrored explicitly right aligned behaves as left aligned
803 text->setHAlign(QQuickText::AlignRight);
804 QCOMPARE(text->hAlign(), QQuickText::AlignRight);
805 QCOMPARE(text->effectiveHAlign(), QQuickText::AlignLeft);
806 QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() < window->width()/2);
808 // mirrored explicitly left aligned behaves as right aligned
809 text->setHAlign(QQuickText::AlignLeft);
810 QCOMPARE(text->hAlign(), QQuickText::AlignLeft);
811 QCOMPARE(text->effectiveHAlign(), QQuickText::AlignRight);
812 QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > window->width()/2);
815 QQuickItemPrivate::get(text)->setLayoutMirror(false);
818 // English text should be implicitly left aligned
819 text->setText("Hello world!");
820 QCOMPARE(text->hAlign(), QQuickText::AlignLeft);
821 QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() < window->width()/2);
823 // empty text with implicit alignment follows the system locale-based
824 // keyboard input direction from QInputMethod::inputDirection()
826 QCOMPARE(text->hAlign(), qApp->inputMethod()->inputDirection() == Qt::LeftToRight ?
827 QQuickText::AlignLeft : QQuickText::AlignRight);
828 text->setHAlign(QQuickText::AlignRight);
829 QCOMPARE(text->hAlign(), QQuickText::AlignRight);
833 // alignment of Text with no text set to it
834 QString componentStr = "import QtQuick 2.0\nText {}";
835 QQmlComponent textComponent(&engine);
836 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
837 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
838 QCOMPARE(textObject->hAlign(), qApp->inputMethod()->inputDirection() == Qt::LeftToRight ?
839 QQuickText::AlignLeft : QQuickText::AlignRight);
843 int tst_qquicktext::numberOfNonWhitePixels(int fromX, int toX, const QImage &image)
846 for (int x = fromX; x < toX; ++x) {
847 for (int y = 0; y < image.height(); ++y) {
848 if (image.pixel(x, y) != qRgb(255, 255, 255))
855 void tst_qquicktext::hAlignImplicitWidth()
857 QQuickView view(testFileUrl("hAlignImplicitWidth.qml"));
859 view.requestActivate();
860 QVERIFY(QTest::qWaitForWindowActive(&view));
862 QQuickText *text = view.rootObject()->findChild<QQuickText*>("textItem");
867 QImage image = view.grabWindow();
868 int left = numberOfNonWhitePixels(0, image.width() / 3, image);
869 int mid = numberOfNonWhitePixels(image.width() / 3, 2 * image.width() / 3, image);
870 int right = numberOfNonWhitePixels( 2 * image.width() / 3, image.width(), image);
872 QVERIFY(mid > right);
876 text->setHAlign(QQuickText::AlignHCenter);
877 QImage image = view.grabWindow();
878 int left = numberOfNonWhitePixels(0, image.width() / 3, image);
879 int mid = numberOfNonWhitePixels(image.width() / 3, 2 * image.width() / 3, image);
880 int right = numberOfNonWhitePixels( 2 * image.width() / 3, image.width(), image);
882 QVERIFY(mid > right);
886 text->setHAlign(QQuickText::AlignRight);
887 QImage image = view.grabWindow();
888 int left = numberOfNonWhitePixels(0, image.width() / 3, image);
889 int mid = numberOfNonWhitePixels(image.width() / 3, 2 * image.width() / 3, image);
890 int right = numberOfNonWhitePixels( 2 * image.width() / 3, image.width(), image);
892 QVERIFY(mid < right);
896 void tst_qquicktext::verticalAlignment()
898 //test one align each, and then test if two align fails.
900 for (int i = 0; i < standard.size(); i++)
902 for (int j=0; j < verticalAlignmentmentStrings.size(); j++)
904 QString componentStr = "import QtQuick 2.0\nText { verticalAlignment: \"" + verticalAlignmentmentStrings.at(j) + "\"; text: \"" + standard.at(i) + "\" }";
905 QQmlComponent textComponent(&engine);
906 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
907 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
909 QVERIFY(textObject != 0);
910 QCOMPARE((int)textObject->vAlign(), (int)verticalAlignmentments.at(j));
916 for (int i = 0; i < richText.size(); i++)
918 for (int j=0; j < verticalAlignmentmentStrings.size(); j++)
920 QString componentStr = "import QtQuick 2.0\nText { verticalAlignment: \"" + verticalAlignmentmentStrings.at(j) + "\"; text: \"" + richText.at(i) + "\" }";
921 QQmlComponent textComponent(&engine);
922 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
923 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
925 QVERIFY(textObject != 0);
926 QCOMPARE((int)textObject->vAlign(), (int)verticalAlignmentments.at(j));
934 void tst_qquicktext::font()
936 //test size, then bold, then italic, then family
938 QString componentStr = "import QtQuick 2.0\nText { font.pointSize: 40; text: \"Hello World\" }";
939 QQmlComponent textComponent(&engine);
940 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
941 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
943 QCOMPARE(textObject->font().pointSize(), 40);
944 QCOMPARE(textObject->font().bold(), false);
945 QCOMPARE(textObject->font().italic(), false);
951 QString componentStr = "import QtQuick 2.0\nText { font.pixelSize: 40; text: \"Hello World\" }";
952 QQmlComponent textComponent(&engine);
953 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
954 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
956 QCOMPARE(textObject->font().pixelSize(), 40);
957 QCOMPARE(textObject->font().bold(), false);
958 QCOMPARE(textObject->font().italic(), false);
964 QString componentStr = "import QtQuick 2.0\nText { font.bold: true; text: \"Hello World\" }";
965 QQmlComponent textComponent(&engine);
966 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
967 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
969 QCOMPARE(textObject->font().bold(), true);
970 QCOMPARE(textObject->font().italic(), false);
976 QString componentStr = "import QtQuick 2.0\nText { font.italic: true; text: \"Hello World\" }";
977 QQmlComponent textComponent(&engine);
978 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
979 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
981 QCOMPARE(textObject->font().italic(), true);
982 QCOMPARE(textObject->font().bold(), false);
988 QString componentStr = "import QtQuick 2.0\nText { font.family: \"Helvetica\"; text: \"Hello World\" }";
989 QQmlComponent textComponent(&engine);
990 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
991 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
993 QCOMPARE(textObject->font().family(), QString("Helvetica"));
994 QCOMPARE(textObject->font().bold(), false);
995 QCOMPARE(textObject->font().italic(), false);
1001 QString componentStr = "import QtQuick 2.0\nText { font.family: \"\"; text: \"Hello World\" }";
1002 QQmlComponent textComponent(&engine);
1003 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1004 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1006 QCOMPARE(textObject->font().family(), QString(""));
1012 void tst_qquicktext::style()
1015 for (int i = 0; i < styles.size(); i++)
1017 QString componentStr = "import QtQuick 2.0\nText { style: \"" + styleStrings.at(i) + "\"; styleColor: \"white\"; text: \"Hello World\" }";
1018 QQmlComponent textComponent(&engine);
1019 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1020 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1022 QCOMPARE((int)textObject->style(), (int)styles.at(i));
1023 QCOMPARE(textObject->styleColor(), QColor("white"));
1027 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello World\" }";
1028 QQmlComponent textComponent(&engine);
1029 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1030 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1032 QRectF brPre = textObject->boundingRect();
1033 textObject->setStyle(QQuickText::Outline);
1034 QRectF brPost = textObject->boundingRect();
1036 QVERIFY(brPre.width() < brPost.width());
1037 QVERIFY(brPre.height() < brPost.height());
1042 void tst_qquicktext::color()
1045 for (int i = 0; i < colorStrings.size(); i++)
1047 QString componentStr = "import QtQuick 2.0\nText { color: \"" + colorStrings.at(i) + "\"; text: \"Hello World\" }";
1048 QQmlComponent textComponent(&engine);
1049 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1050 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1052 QCOMPARE(textObject->color(), QColor(colorStrings.at(i)));
1053 QCOMPARE(textObject->styleColor(), QColor("black"));
1054 QCOMPARE(textObject->linkColor(), QColor("blue"));
1059 for (int i = 0; i < colorStrings.size(); i++)
1061 QString componentStr = "import QtQuick 2.0\nText { styleColor: \"" + colorStrings.at(i) + "\"; text: \"Hello World\" }";
1062 QQmlComponent textComponent(&engine);
1063 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1064 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1066 QCOMPARE(textObject->styleColor(), QColor(colorStrings.at(i)));
1067 // default color to black?
1068 QCOMPARE(textObject->color(), QColor("black"));
1069 QCOMPARE(textObject->linkColor(), QColor("blue"));
1071 QSignalSpy colorSpy(textObject, SIGNAL(colorChanged()));
1072 QSignalSpy linkColorSpy(textObject, SIGNAL(linkColorChanged()));
1074 textObject->setColor(QColor("white"));
1075 QCOMPARE(textObject->color(), QColor("white"));
1076 QCOMPARE(colorSpy.count(), 1);
1078 textObject->setLinkColor(QColor("black"));
1079 QCOMPARE(textObject->linkColor(), QColor("black"));
1080 QCOMPARE(linkColorSpy.count(), 1);
1082 textObject->setColor(QColor("white"));
1083 QCOMPARE(colorSpy.count(), 1);
1085 textObject->setLinkColor(QColor("black"));
1086 QCOMPARE(linkColorSpy.count(), 1);
1088 textObject->setColor(QColor("black"));
1089 QCOMPARE(textObject->color(), QColor("black"));
1090 QCOMPARE(colorSpy.count(), 2);
1092 textObject->setLinkColor(QColor("blue"));
1093 QCOMPARE(textObject->linkColor(), QColor("blue"));
1094 QCOMPARE(linkColorSpy.count(), 2);
1099 for (int i = 0; i < colorStrings.size(); i++)
1101 QString componentStr = "import QtQuick 2.0\nText { linkColor: \"" + colorStrings.at(i) + "\"; text: \"Hello World\" }";
1102 QQmlComponent textComponent(&engine);
1103 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1104 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1106 QCOMPARE(textObject->styleColor(), QColor("black"));
1107 QCOMPARE(textObject->color(), QColor("black"));
1108 QCOMPARE(textObject->linkColor(), QColor(colorStrings.at(i)));
1113 for (int i = 0; i < colorStrings.size(); i++)
1115 for (int j = 0; j < colorStrings.size(); j++)
1117 QString componentStr = "import QtQuick 2.0\nText { "
1118 "color: \"" + colorStrings.at(i) + "\"; "
1119 "styleColor: \"" + colorStrings.at(j) + "\"; "
1120 "linkColor: \"" + colorStrings.at(j) + "\"; "
1121 "text: \"Hello World\" }";
1122 QQmlComponent textComponent(&engine);
1123 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1124 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1126 QCOMPARE(textObject->color(), QColor(colorStrings.at(i)));
1127 QCOMPARE(textObject->styleColor(), QColor(colorStrings.at(j)));
1128 QCOMPARE(textObject->linkColor(), QColor(colorStrings.at(j)));
1134 QString colorStr = "#AA001234";
1135 QColor testColor("#001234");
1136 testColor.setAlpha(170);
1138 QString componentStr = "import QtQuick 2.0\nText { color: \"" + colorStr + "\"; text: \"Hello World\" }";
1139 QQmlComponent textComponent(&engine);
1140 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1141 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1143 QCOMPARE(textObject->color(), testColor);
1147 QString colorStr = "#001234";
1148 QColor testColor(colorStr);
1150 QString componentStr = "import QtQuick 2.0\nText { color: \"" + colorStr + "\"; text: \"Hello World\" }";
1151 QQmlComponent textComponent(&engine);
1152 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1153 QScopedPointer<QObject> object(textComponent.create());
1154 QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
1156 QSignalSpy spy(textObject, SIGNAL(colorChanged()));
1158 QCOMPARE(textObject->color(), testColor);
1159 textObject->setColor(testColor);
1160 QCOMPARE(textObject->color(), testColor);
1161 QCOMPARE(spy.count(), 0);
1163 testColor = QColor("black");
1164 textObject->setColor(testColor);
1165 QCOMPARE(textObject->color(), testColor);
1166 QCOMPARE(spy.count(), 1);
1168 QString colorStr = "#001234";
1169 QColor testColor(colorStr);
1171 QString componentStr = "import QtQuick 2.0\nText { styleColor: \"" + colorStr + "\"; text: \"Hello World\" }";
1172 QQmlComponent textComponent(&engine);
1173 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1174 QScopedPointer<QObject> object(textComponent.create());
1175 QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
1177 QSignalSpy spy(textObject, SIGNAL(styleColorChanged()));
1179 QCOMPARE(textObject->styleColor(), testColor);
1180 textObject->setStyleColor(testColor);
1181 QCOMPARE(textObject->styleColor(), testColor);
1182 QCOMPARE(spy.count(), 0);
1184 testColor = QColor("black");
1185 textObject->setStyleColor(testColor);
1186 QCOMPARE(textObject->styleColor(), testColor);
1187 QCOMPARE(spy.count(), 1);
1189 QString colorStr = "#001234";
1190 QColor testColor(colorStr);
1192 QString componentStr = "import QtQuick 2.0\nText { linkColor: \"" + colorStr + "\"; text: \"Hello World\" }";
1193 QQmlComponent textComponent(&engine);
1194 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1195 QScopedPointer<QObject> object(textComponent.create());
1196 QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
1198 QSignalSpy spy(textObject, SIGNAL(linkColorChanged()));
1200 QCOMPARE(textObject->linkColor(), testColor);
1201 textObject->setLinkColor(testColor);
1202 QCOMPARE(textObject->linkColor(), testColor);
1203 QCOMPARE(spy.count(), 0);
1205 testColor = QColor("black");
1206 textObject->setLinkColor(testColor);
1207 QCOMPARE(textObject->linkColor(), testColor);
1208 QCOMPARE(spy.count(), 1);
1212 void tst_qquicktext::smooth()
1214 for (int i = 0; i < standard.size(); i++)
1217 QString componentStr = "import QtQuick 2.0\nText { smooth: false; text: \"" + standard.at(i) + "\" }";
1218 QQmlComponent textComponent(&engine);
1219 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1220 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1221 QCOMPARE(textObject->smooth(), false);
1226 QString componentStr = "import QtQuick 2.0\nText { text: \"" + standard.at(i) + "\" }";
1227 QQmlComponent textComponent(&engine);
1228 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1229 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1230 QCOMPARE(textObject->smooth(), true);
1235 for (int i = 0; i < richText.size(); i++)
1238 QString componentStr = "import QtQuick 2.0\nText { smooth: false; text: \"" + richText.at(i) + "\" }";
1239 QQmlComponent textComponent(&engine);
1240 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1241 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1242 QCOMPARE(textObject->smooth(), false);
1247 QString componentStr = "import QtQuick 2.0\nText { text: \"" + richText.at(i) + "\" }";
1248 QQmlComponent textComponent(&engine);
1249 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1250 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1251 QCOMPARE(textObject->smooth(), true);
1258 void tst_qquicktext::renderType()
1260 QQmlComponent component(&engine);
1261 component.setData("import QtQuick 2.0\n Text {}", QUrl());
1262 QScopedPointer<QObject> object(component.create());
1263 QQuickText *text = qobject_cast<QQuickText *>(object.data());
1266 QSignalSpy spy(text, SIGNAL(renderTypeChanged()));
1268 QCOMPARE(text->renderType(), QQuickText::QtRendering);
1270 text->setRenderType(QQuickText::NativeRendering);
1271 QCOMPARE(text->renderType(), QQuickText::NativeRendering);
1272 QCOMPARE(spy.count(), 1);
1274 text->setRenderType(QQuickText::NativeRendering);
1275 QCOMPARE(spy.count(), 1);
1277 text->setRenderType(QQuickText::QtRendering);
1278 QCOMPARE(text->renderType(), QQuickText::QtRendering);
1279 QCOMPARE(spy.count(), 2);
1282 void tst_qquicktext::weight()
1285 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
1286 QQmlComponent textComponent(&engine);
1287 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1288 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1290 QVERIFY(textObject != 0);
1291 QCOMPARE((int)textObject->font().weight(), (int)QQuickFontValueType::Normal);
1296 QString componentStr = "import QtQuick 2.0\nText { font.weight: \"Bold\"; text: \"Hello world!\" }";
1297 QQmlComponent textComponent(&engine);
1298 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1299 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1301 QVERIFY(textObject != 0);
1302 QCOMPARE((int)textObject->font().weight(), (int)QQuickFontValueType::Bold);
1308 void tst_qquicktext::underline()
1310 QQuickView view(testFileUrl("underline.qml"));
1312 view.requestActivate();
1313 QVERIFY(QTest::qWaitForWindowActive(&view));
1314 QQuickText *textObject = view.rootObject()->findChild<QQuickText*>("myText");
1315 QVERIFY(textObject != 0);
1316 QCOMPARE(textObject->font().overline(), false);
1317 QCOMPARE(textObject->font().underline(), true);
1318 QCOMPARE(textObject->font().strikeOut(), false);
1321 void tst_qquicktext::overline()
1323 QQuickView view(testFileUrl("overline.qml"));
1325 view.requestActivate();
1326 QVERIFY(QTest::qWaitForWindowActive(&view));
1327 QQuickText *textObject = view.rootObject()->findChild<QQuickText*>("myText");
1328 QVERIFY(textObject != 0);
1329 QCOMPARE(textObject->font().overline(), true);
1330 QCOMPARE(textObject->font().underline(), false);
1331 QCOMPARE(textObject->font().strikeOut(), false);
1334 void tst_qquicktext::strikeout()
1336 QQuickView view(testFileUrl("strikeout.qml"));
1338 view.requestActivate();
1339 QVERIFY(QTest::qWaitForWindowActive(&view));
1340 QQuickText *textObject = view.rootObject()->findChild<QQuickText*>("myText");
1341 QVERIFY(textObject != 0);
1342 QCOMPARE(textObject->font().overline(), false);
1343 QCOMPARE(textObject->font().underline(), false);
1344 QCOMPARE(textObject->font().strikeOut(), true);
1347 void tst_qquicktext::capitalization()
1350 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
1351 QQmlComponent textComponent(&engine);
1352 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1353 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1355 QVERIFY(textObject != 0);
1356 QCOMPARE((int)textObject->font().capitalization(), (int)QQuickFontValueType::MixedCase);
1361 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.capitalization: \"AllUppercase\" }";
1362 QQmlComponent textComponent(&engine);
1363 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1364 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1366 QVERIFY(textObject != 0);
1367 QCOMPARE((int)textObject->font().capitalization(), (int)QQuickFontValueType::AllUppercase);
1372 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.capitalization: \"AllLowercase\" }";
1373 QQmlComponent textComponent(&engine);
1374 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1375 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1377 QVERIFY(textObject != 0);
1378 QCOMPARE((int)textObject->font().capitalization(), (int)QQuickFontValueType::AllLowercase);
1383 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.capitalization: \"SmallCaps\" }";
1384 QQmlComponent textComponent(&engine);
1385 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1386 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1388 QVERIFY(textObject != 0);
1389 QCOMPARE((int)textObject->font().capitalization(), (int)QQuickFontValueType::SmallCaps);
1394 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.capitalization: \"Capitalize\" }";
1395 QQmlComponent textComponent(&engine);
1396 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1397 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1399 QVERIFY(textObject != 0);
1400 QCOMPARE((int)textObject->font().capitalization(), (int)QQuickFontValueType::Capitalize);
1406 void tst_qquicktext::letterSpacing()
1409 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
1410 QQmlComponent textComponent(&engine);
1411 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1412 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1414 QVERIFY(textObject != 0);
1415 QCOMPARE(textObject->font().letterSpacing(), 0.0);
1420 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.letterSpacing: -2 }";
1421 QQmlComponent textComponent(&engine);
1422 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1423 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1425 QVERIFY(textObject != 0);
1426 QCOMPARE(textObject->font().letterSpacing(), -2.);
1431 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.letterSpacing: 3 }";
1432 QQmlComponent textComponent(&engine);
1433 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1434 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1436 QVERIFY(textObject != 0);
1437 QCOMPARE(textObject->font().letterSpacing(), 3.);
1443 void tst_qquicktext::wordSpacing()
1446 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
1447 QQmlComponent textComponent(&engine);
1448 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1449 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1451 QVERIFY(textObject != 0);
1452 QCOMPARE(textObject->font().wordSpacing(), 0.0);
1457 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.wordSpacing: -50 }";
1458 QQmlComponent textComponent(&engine);
1459 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1460 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1462 QVERIFY(textObject != 0);
1463 QCOMPARE(textObject->font().wordSpacing(), -50.);
1468 QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.wordSpacing: 200 }";
1469 QQmlComponent textComponent(&engine);
1470 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1471 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1473 QVERIFY(textObject != 0);
1474 QCOMPARE(textObject->font().wordSpacing(), 200.);
1480 class EventSender : public QQuickItem
1483 void sendEvent(QMouseEvent *event) {
1484 if (event->type() == QEvent::MouseButtonPress)
1485 mousePressEvent(event);
1486 else if (event->type() == QEvent::MouseButtonRelease)
1487 mouseReleaseEvent(event);
1488 else if (event->type() == QEvent::MouseMove)
1489 mouseMoveEvent(event);
1491 qWarning() << "Trying to send unsupported event type";
1495 class LinkTest : public QObject
1504 void linkClicked(QString l) { link = l; }
1510 TextMetrics(const QString &text, Qt::TextElideMode elideMode = Qt::ElideNone)
1512 QString adjustedText = text;
1513 adjustedText.replace(QLatin1Char('\n'), QChar(QChar::LineSeparator));
1514 if (elideMode == Qt::ElideLeft)
1515 adjustedText = QChar(0x2026) + adjustedText;
1516 else if (elideMode == Qt::ElideRight)
1517 adjustedText = adjustedText + QChar(0x2026);
1519 layout.setText(adjustedText);
1521 option.setUseDesignMetrics(true);
1522 layout.setTextOption(option);
1524 layout.beginLayout();
1526 QTextLine line = layout.createLine();
1527 while (line.isValid()) {
1528 line.setLineWidth(FLT_MAX);
1529 line.setPosition(QPointF(0, height));
1530 height += line.height();
1531 line = layout.createLine();
1536 qreal width() const { return layout.maximumWidth(); }
1538 QRectF characterRectangle(
1540 int hAlign = Qt::AlignLeft,
1541 int vAlign = Qt::AlignTop,
1542 const QSizeF &bounds = QSizeF(240, 320)) const
1546 case Qt::AlignBottom:
1547 dy = bounds.height() - layout.boundingRect().height();
1549 case Qt::AlignVCenter:
1550 dy = (bounds.height() - layout.boundingRect().height()) / 2;
1556 for (int i = 0; i < layout.lineCount(); ++i) {
1557 QTextLine line = layout.lineAt(i);
1558 if (position >= line.textStart() + line.textLength())
1562 case Qt::AlignRight:
1563 dx = bounds.width() - line.naturalTextWidth();
1565 case Qt::AlignHCenter:
1566 dx = (bounds.width() - line.naturalTextWidth()) / 2;
1573 rect.setLeft(dx + line.cursorToX(position, QTextLine::Leading));
1574 rect.setRight(dx + line.cursorToX(position, QTextLine::Trailing));
1575 rect.setTop(dy + line.y());
1576 rect.setBottom(dy + line.y() + line.height());
1587 typedef QVector<QPointF> PointVector;
1588 Q_DECLARE_METATYPE(PointVector);
1590 void tst_qquicktext::clickLink_data()
1592 QTest::addColumn<QString>("text");
1593 QTest::addColumn<qreal>("width");
1594 QTest::addColumn<QString>("bindings");
1595 QTest::addColumn<PointVector>("mousePositions");
1596 QTest::addColumn<QString>("link");
1598 const QString singleLineText = "this text has a <a href=\\\"http://qt-project.org/single\\\">link</a> in it";
1599 const QString singleLineLink = "http://qt-project.org/single";
1600 const QString multipleLineText = "this text<br/>has <a href=\\\"http://qt-project.org/multiple\\\">multiple<br/>lines</a> in it";
1601 const QString multipleLineLink = "http://qt-project.org/multiple";
1602 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>";
1603 const QString outerLink = "http://qt-project.org/outer";
1604 const QString innerLink = "http://qt-project.org/inner";
1607 const TextMetrics metrics("this text has a link in it");
1609 QTest::newRow("click on link")
1610 << singleLineText << 240.
1612 << (PointVector() << metrics.characterRectangle(18).center())
1614 QTest::newRow("click on text")
1615 << singleLineText << 240.
1617 << (PointVector() << metrics.characterRectangle(13).center())
1619 QTest::newRow("drag within link")
1620 << singleLineText << 240.
1623 << metrics.characterRectangle(17).center()
1624 << metrics.characterRectangle(19).center())
1626 QTest::newRow("drag away from link")
1627 << singleLineText << 240.
1630 << metrics.characterRectangle(18).center()
1631 << metrics.characterRectangle(13).center())
1633 QTest::newRow("drag on to link")
1634 << singleLineText << 240.
1637 << metrics.characterRectangle(13).center()
1638 << metrics.characterRectangle(18).center())
1640 QTest::newRow("click on bottom right aligned link")
1641 << singleLineText << 240.
1642 << "horizontalAlignment: Text.AlignRight; verticalAlignment: Text.AlignBottom"
1643 << (PointVector() << metrics.characterRectangle(18, Qt::AlignRight, Qt::AlignBottom).center())
1645 QTest::newRow("click on center aligned link")
1646 << singleLineText << 240.
1647 << "horizontalAlignment: Text.AlignHCenter; verticalAlignment: Text.AlignVCenter"
1648 << (PointVector() << metrics.characterRectangle(18, Qt::AlignHCenter, Qt::AlignVCenter).center())
1650 QTest::newRow("click on rich text link")
1651 << singleLineText << 240.
1652 << "textFormat: Text.RichText"
1653 << (PointVector() << metrics.characterRectangle(18).center())
1655 QTest::newRow("click on rich text")
1656 << singleLineText << 240.
1657 << "textFormat: Text.RichText"
1658 << (PointVector() << metrics.characterRectangle(13).center())
1660 QTest::newRow("click on bottom right aligned rich text link")
1661 << singleLineText << 240.
1662 << "textFormat: Text.RichText; horizontalAlignment: Text.AlignRight; verticalAlignment: Text.AlignBottom"
1663 << (PointVector() << metrics.characterRectangle(18, Qt::AlignRight, Qt::AlignBottom).center())
1665 QTest::newRow("click on center aligned rich text link")
1666 << singleLineText << 240.
1667 << "textFormat: Text.RichText; horizontalAlignment: Text.AlignHCenter; verticalAlignment: Text.AlignVCenter"
1668 << (PointVector() << metrics.characterRectangle(18, Qt::AlignHCenter, Qt::AlignVCenter).center())
1671 const TextMetrics metrics("this text has a li", Qt::ElideRight);
1672 QTest::newRow("click on right elided link")
1673 << singleLineText << metrics.width() + 2
1674 << "elide: Text.ElideRight"
1675 << (PointVector() << metrics.characterRectangle(17).center())
1678 const TextMetrics metrics("ink in it", Qt::ElideLeft);
1679 QTest::newRow("click on left elided link")
1680 << singleLineText << metrics.width() + 2
1681 << "elide: Text.ElideLeft"
1682 << (PointVector() << metrics.characterRectangle(2).center())
1685 const TextMetrics metrics("this text\nhas multiple\nlines in it");
1686 QTest::newRow("click on second line")
1687 << multipleLineText << 240.
1689 << (PointVector() << metrics.characterRectangle(18).center())
1690 << multipleLineLink;
1691 QTest::newRow("click on third line")
1692 << multipleLineText << 240.
1694 << (PointVector() << metrics.characterRectangle(25).center())
1695 << multipleLineLink;
1696 QTest::newRow("drag from second line to third")
1697 << multipleLineText << 240.
1700 << metrics.characterRectangle(18).center()
1701 << metrics.characterRectangle(25).center())
1702 << multipleLineLink;
1703 QTest::newRow("click on rich text second line")
1704 << multipleLineText << 240.
1705 << "textFormat: Text.RichText"
1706 << (PointVector() << metrics.characterRectangle(18).center())
1707 << multipleLineLink;
1708 QTest::newRow("click on rich text third line")
1709 << multipleLineText << 240.
1710 << "textFormat: Text.RichText"
1711 << (PointVector() << metrics.characterRectangle(25).center())
1712 << multipleLineLink;
1713 QTest::newRow("drag rich text from second line to third")
1714 << multipleLineText << 240.
1715 << "textFormat: Text.RichText"
1717 << metrics.characterRectangle(18).center()
1718 << metrics.characterRectangle(25).center())
1719 << multipleLineLink;
1721 const TextMetrics metrics("this text has a nested link in it");
1722 QTest::newRow("click on left outer link")
1723 << nestedText << 240.
1725 << (PointVector() << metrics.characterRectangle(22).center())
1727 QTest::newRow("click on right outer link")
1728 << nestedText << 240.
1730 << (PointVector() << metrics.characterRectangle(27).center())
1732 QTest::newRow("click on inner link left")
1733 << nestedText << 240.
1735 << (PointVector() << metrics.characterRectangle(23).center())
1737 QTest::newRow("click on inner link right")
1738 << nestedText << 240.
1740 << (PointVector() << metrics.characterRectangle(26).center())
1742 QTest::newRow("drag from inner to outer link")
1743 << nestedText << 240.
1746 << metrics.characterRectangle(25).center()
1747 << metrics.characterRectangle(30).center())
1749 QTest::newRow("drag from outer to inner link")
1750 << nestedText << 240.
1753 << metrics.characterRectangle(30).center()
1754 << metrics.characterRectangle(25).center())
1756 QTest::newRow("click on left outer rich text link")
1757 << nestedText << 240.
1758 << "textFormat: Text.RichText"
1759 << (PointVector() << metrics.characterRectangle(22).center())
1761 QTest::newRow("click on right outer rich text link")
1762 << nestedText << 240.
1763 << "textFormat: Text.RichText"
1764 << (PointVector() << metrics.characterRectangle(27).center())
1766 QTest::newRow("click on inner rich text link left")
1767 << nestedText << 240.
1768 << "textFormat: Text.RichText"
1769 << (PointVector() << metrics.characterRectangle(23).center())
1771 QTest::newRow("click on inner rich text link right")
1772 << nestedText << 240.
1773 << "textFormat: Text.RichText"
1774 << (PointVector() << metrics.characterRectangle(26).center())
1776 QTest::newRow("drag from inner to outer rich text link")
1777 << nestedText << 240.
1778 << "textFormat: Text.RichText"
1780 << metrics.characterRectangle(25).center()
1781 << metrics.characterRectangle(30).center())
1783 QTest::newRow("drag from outer to inner rich text link")
1784 << nestedText << 240.
1785 << "textFormat: Text.RichText"
1787 << metrics.characterRectangle(30).center()
1788 << metrics.characterRectangle(25).center())
1793 void tst_qquicktext::clickLink()
1795 QFETCH(QString, text);
1796 QFETCH(qreal, width);
1797 QFETCH(QString, bindings);
1798 QFETCH(PointVector, mousePositions);
1799 QFETCH(QString, link);
1801 QString componentStr =
1802 "import QtQuick 2.0\nText {\n"
1803 "width: " + QString::number(width) + "\n"
1805 "text: \"" + text + "\"\n"
1806 "" + bindings + "\n"
1808 QQmlComponent textComponent(&engine);
1809 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1810 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1812 QVERIFY(textObject != 0);
1815 QObject::connect(textObject, SIGNAL(linkActivated(QString)), &test, SLOT(linkClicked(QString)));
1817 QVERIFY(mousePositions.count() > 0);
1819 QPointF mousePosition = mousePositions.first();
1821 QMouseEvent me(QEvent::MouseButtonPress, mousePosition, Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
1822 static_cast<EventSender*>(static_cast<QQuickItem*>(textObject))->sendEvent(&me);
1825 for (int i = 1; i < mousePositions.count(); ++i) {
1826 mousePosition = mousePositions.at(i);
1828 QMouseEvent me(QEvent::MouseMove, mousePosition, Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
1829 static_cast<EventSender*>(static_cast<QQuickItem*>(textObject))->sendEvent(&me);
1833 QMouseEvent me(QEvent::MouseButtonRelease, mousePosition, Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
1834 static_cast<EventSender*>(static_cast<QQuickItem*>(textObject))->sendEvent(&me);
1837 QCOMPARE(test.link, link);
1842 void tst_qquicktext::baseUrl()
1844 QUrl localUrl("file:///tests/text.qml");
1845 QUrl remoteUrl("http://qt.nokia.com/test.qml");
1847 QQmlComponent textComponent(&engine);
1848 textComponent.setData("import QtQuick 2.0\n Text {}", localUrl);
1849 QQuickText *textObject = qobject_cast<QQuickText *>(textComponent.create());
1851 QCOMPARE(textObject->baseUrl(), localUrl);
1853 QSignalSpy spy(textObject, SIGNAL(baseUrlChanged()));
1855 textObject->setBaseUrl(localUrl);
1856 QCOMPARE(textObject->baseUrl(), localUrl);
1857 QCOMPARE(spy.count(), 0);
1859 textObject->setBaseUrl(remoteUrl);
1860 QCOMPARE(textObject->baseUrl(), remoteUrl);
1861 QCOMPARE(spy.count(), 1);
1863 textObject->resetBaseUrl();
1864 QCOMPARE(textObject->baseUrl(), localUrl);
1865 QCOMPARE(spy.count(), 2);
1868 void tst_qquicktext::embeddedImages_data()
1870 QTest::addColumn<QUrl>("qmlfile");
1871 QTest::addColumn<QString>("error");
1872 QTest::newRow("local") << testFileUrl("embeddedImagesLocal.qml") << "";
1873 QTest::newRow("local-error") << testFileUrl("embeddedImagesLocalError.qml")
1874 << testFileUrl("embeddedImagesLocalError.qml").toString()+":3:1: QML Text: Cannot open: " + testFileUrl("http/notexists.png").toString();
1875 QTest::newRow("local") << testFileUrl("embeddedImagesLocalRelative.qml") << "";
1876 QTest::newRow("remote") << testFileUrl("embeddedImagesRemote.qml") << "";
1877 QTest::newRow("remote-error") << testFileUrl("embeddedImagesRemoteError.qml")
1878 << testFileUrl("embeddedImagesRemoteError.qml").toString()+":3:1: QML Text: Error downloading " SERVER_ADDR "/notexists.png - server replied: Not found";
1879 QTest::newRow("remote") << testFileUrl("embeddedImagesRemoteRelative.qml") << "";
1882 void tst_qquicktext::embeddedImages()
1886 QFETCH(QUrl, qmlfile);
1887 QFETCH(QString, error);
1889 TestHTTPServer server(SERVER_PORT);
1890 server.serveDirectory(testFile("http"));
1892 if (!error.isEmpty())
1893 QTest::ignoreMessage(QtWarningMsg, error.toLatin1());
1895 QQuickView *view = new QQuickView(qmlfile);
1897 view->requestActivate();
1898 QVERIFY(QTest::qWaitForWindowActive(view));
1899 QQuickText *textObject = qobject_cast<QQuickText*>(view->rootObject());
1901 QVERIFY(textObject != 0);
1902 QTRY_COMPARE(textObject->resourcesLoading(), 0);
1904 QPixmap pm(testFile("http/exists.png"));
1905 if (error.isEmpty()) {
1906 QCOMPARE(textObject->width(), double(pm.width()));
1907 QCOMPARE(textObject->height(), double(pm.height()));
1909 QVERIFY(16 != pm.width()); // check test is effective
1910 QCOMPARE(textObject->width(), 16.0); // default size of QTextDocument broken image icon
1911 QCOMPARE(textObject->height(), 16.0);
1917 void tst_qquicktext::lineCount()
1919 QQuickView *window = createView(testFile("lineCount.qml"));
1921 QQuickText *myText = window->rootObject()->findChild<QQuickText*>("myText");
1922 QVERIFY(myText != 0);
1924 QVERIFY(myText->lineCount() > 1);
1925 QVERIFY(!myText->truncated());
1926 QCOMPARE(myText->maximumLineCount(), INT_MAX);
1928 myText->setMaximumLineCount(2);
1929 QCOMPARE(myText->lineCount(), 2);
1930 QCOMPARE(myText->truncated(), true);
1931 QCOMPARE(myText->maximumLineCount(), 2);
1933 myText->resetMaximumLineCount();
1934 QCOMPARE(myText->maximumLineCount(), INT_MAX);
1935 QCOMPARE(myText->truncated(), false);
1937 myText->setElideMode(QQuickText::ElideRight);
1938 myText->setMaximumLineCount(2);
1939 QCOMPARE(myText->lineCount(), 2);
1940 QCOMPARE(myText->truncated(), true);
1941 QCOMPARE(myText->maximumLineCount(), 2);
1946 void tst_qquicktext::lineHeight()
1948 QQuickView *window = createView(testFile("lineHeight.qml"));
1950 QQuickText *myText = window->rootObject()->findChild<QQuickText*>("myText");
1951 QVERIFY(myText != 0);
1953 QVERIFY(myText->lineHeight() == 1);
1954 QVERIFY(myText->lineHeightMode() == QQuickText::ProportionalHeight);
1956 qreal h = myText->height();
1957 myText->setLineHeight(1.5);
1958 QCOMPARE(myText->height(), qreal(qCeil(h)) * 1.5);
1960 myText->setLineHeightMode(QQuickText::FixedHeight);
1961 myText->setLineHeight(20);
1962 QCOMPARE(myText->height(), myText->lineCount() * 20.0);
1964 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.");
1965 myText->setLineHeightMode(QQuickText::ProportionalHeight);
1966 myText->setLineHeight(1.0);
1968 qreal h2 = myText->height();
1969 myText->setLineHeight(2.0);
1970 QVERIFY(myText->height() == h2 * 2.0);
1972 myText->setLineHeightMode(QQuickText::FixedHeight);
1973 myText->setLineHeight(10);
1974 QCOMPARE(myText->height(), myText->lineCount() * 10.0);
1979 void tst_qquicktext::implicitSize_data()
1981 QTest::addColumn<QString>("text");
1982 QTest::addColumn<QString>("width");
1983 QTest::addColumn<QString>("wrap");
1984 QTest::addColumn<QString>("elide");
1985 QTest::addColumn<QString>("format");
1986 QTest::newRow("plain") << "The quick red fox jumped over the lazy brown dog" << "50" << "Text.NoWrap" << "Text.ElideNone" << "Text.PlainText";
1987 QTest::newRow("richtext") << "<b>The quick red fox jumped over the lazy brown dog</b>" <<" 50" << "Text.NoWrap" << "Text.ElideNone" << "Text.RichText";
1988 QTest::newRow("styledtext") << "<b>The quick red fox jumped over the lazy brown dog</b>" <<" 50" << "Text.NoWrap" << "Text.ElideNone" << "Text.StyledText";
1989 QTest::newRow("plain, 0 width") << "The quick red fox jumped over the lazy brown dog" << "0" << "Text.NoWrap" << "Text.ElideNone" << "Text.PlainText";
1990 QTest::newRow("plain, elide") << "The quick red fox jumped over the lazy brown dog" << "50" << "Text.NoWrap" << "Text.ElideRight" << "Text.PlainText";
1991 QTest::newRow("plain, 0 width, elide") << "The quick red fox jumped over the lazy brown dog" << "0" << "Text.NoWrap" << "Text.ElideRight" << "Text.PlainText";
1992 QTest::newRow("richtext, 0 width") << "<b>The quick red fox jumped over the lazy brown dog</b>" <<" 0" << "Text.NoWrap" << "Text.ElideNone" << "Text.RichText";
1993 QTest::newRow("styledtext, 0 width") << "<b>The quick red fox jumped over the lazy brown dog</b>" <<" 0" << "Text.NoWrap" << "Text.ElideNone" << "Text.StyledText";
1994 QTest::newRow("plain_wrap") << "The quick red fox jumped over the lazy brown dog" << "50" << "Text.Wrap" << "Text.ElideNone" << "Text.PlainText";
1995 QTest::newRow("richtext_wrap") << "<b>The quick red fox jumped over the lazy brown dog</b>" << "50" << "Text.Wrap" << "Text.ElideNone" << "Text.RichText";
1996 QTest::newRow("styledtext_wrap") << "<b>The quick red fox jumped over the lazy brown dog</b>" << "50" << "Text.Wrap" << "Text.ElideNone" << "Text.StyledText";
1997 QTest::newRow("plain_wrap, 0 width") << "The quick red fox jumped over the lazy brown dog" << "0" << "Text.Wrap" << "Text.ElideNone" << "Text.PlainText";
1998 QTest::newRow("plain_wrap, elide") << "The quick red fox jumped over the lazy brown dog" << "50" << "Text.Wrap" << "Text.ElideRight" << "Text.PlainText";
1999 QTest::newRow("plain_wrap, 0 width, elide") << "The quick red fox jumped over the lazy brown dog" << "0" << "Text.Wrap" << "Text.ElideRight" << "Text.PlainText";
2000 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";
2001 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";
2004 void tst_qquicktext::implicitSize()
2006 QFETCH(QString, text);
2007 QFETCH(QString, width);
2008 QFETCH(QString, format);
2009 QFETCH(QString, wrap);
2010 QFETCH(QString, elide);
2011 QString componentStr = "import QtQuick 2.0\nText { "
2012 "property real iWidth: implicitWidth; "
2013 "text: \"" + text + "\"; "
2014 "width: " + width + "; "
2015 "textFormat: " + format + "; "
2016 "wrapMode: " + wrap + "; "
2017 "elide: " + elide + "; "
2018 "maximumLineCount: 2 }";
2019 QQmlComponent textComponent(&engine);
2020 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
2021 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
2023 QVERIFY(textObject->width() < textObject->implicitWidth());
2024 QVERIFY(textObject->height() == textObject->implicitHeight());
2025 QCOMPARE(textObject->property("iWidth").toReal(), textObject->implicitWidth());
2027 textObject->resetWidth();
2028 QVERIFY(textObject->width() == textObject->implicitWidth());
2029 QVERIFY(textObject->height() == textObject->implicitHeight());
2034 void tst_qquicktext::contentSize()
2036 QString componentStr = "import QtQuick 2.0\nText { width: 75; height: 16; font.pixelSize: 10 }";
2037 QQmlComponent textComponent(&engine);
2038 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
2039 QScopedPointer<QObject> object(textComponent.create());
2040 QQuickText *textObject = qobject_cast<QQuickText *>(object.data());
2042 QSignalSpy spy(textObject, SIGNAL(contentSizeChanged()));
2044 textObject->setText("The quick red fox jumped over the lazy brown dog");
2046 QVERIFY(textObject->contentWidth() > textObject->width());
2047 QVERIFY(textObject->contentHeight() < textObject->height());
2048 QCOMPARE(spy.count(), 1);
2050 textObject->setWrapMode(QQuickText::WordWrap);
2051 QVERIFY(textObject->contentWidth() <= textObject->width());
2052 QVERIFY(textObject->contentHeight() > textObject->height());
2053 QCOMPARE(spy.count(), 2);
2055 textObject->setElideMode(QQuickText::ElideRight);
2056 QVERIFY(textObject->contentWidth() <= textObject->width());
2057 QVERIFY(textObject->contentHeight() < textObject->height());
2058 QCOMPARE(spy.count(), 3);
2060 qreal elidedWidth = textObject->contentWidth();
2062 textObject->setText("The quickredfoxjumpedoverthe lazy brown dog");
2063 QVERIFY(textObject->contentWidth() <= textObject->width());
2064 QVERIFY(textObject->contentHeight() < textObject->height());
2065 // this text probably won't have the same elided width, but it's not guaranteed.
2066 if (textObject->contentWidth() != elidedWidth)
2067 QCOMPARE(spy.count(), ++spyCount);
2069 QCOMPARE(spy.count(), spyCount);
2071 textObject->setElideMode(QQuickText::ElideNone);
2072 QVERIFY(textObject->contentWidth() > textObject->width());
2073 QVERIFY(textObject->contentHeight() > textObject->height());
2074 QCOMPARE(spy.count(), ++spyCount);
2077 void tst_qquicktext::geometryChanged()
2079 // Test that text is re-laid out when the geometry of the item by verifying changes in content
2080 // size. Implicit width is also tested as that in combination with item geometry provides a
2081 // reference for expected content sizes.
2083 QString componentStr = "import QtQuick 2.0\nText { font.family: \"__Qt__Box__Engine__\"; font.pixelSize: 10 }";
2084 QQmlComponent textComponent(&engine);
2085 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
2086 QScopedPointer<QObject> object(textComponent.create());
2087 QQuickText *textObject = qobject_cast<QQuickText *>(object.data());
2089 const qreal implicitHeight = textObject->implicitHeight();
2091 const qreal widths[] = { 100, 2000, 3000, -100, 100 };
2092 const qreal heights[] = { implicitHeight, 2000, 3000, -implicitHeight, implicitHeight };
2094 QCOMPARE(textObject->implicitWidth(), 0.);
2095 QVERIFY(implicitHeight > 0.);
2096 QCOMPARE(textObject->width(), textObject->implicitWidth());
2097 QCOMPARE(textObject->height(), implicitHeight);
2098 QCOMPARE(textObject->contentWidth(), textObject->implicitWidth());
2099 QCOMPARE(textObject->contentHeight(), implicitHeight);
2101 textObject->setText("The quick red fox jumped over the lazy brown dog");
2103 const qreal implicitWidth = textObject->implicitWidth();
2105 QVERIFY(implicitWidth > 0.);
2106 QCOMPARE(textObject->implicitHeight(), implicitHeight);
2107 QCOMPARE(textObject->width(), textObject->implicitWidth());
2108 QCOMPARE(textObject->height(), textObject->implicitHeight());
2109 QCOMPARE(textObject->contentWidth(), textObject->implicitWidth());
2110 QCOMPARE(textObject->contentHeight(), textObject->implicitHeight());
2112 // Changing the geometry with no eliding, or wrapping doesn't change the content size.
2113 for (int i = 0; i < 5; ++i) {
2114 textObject->setWidth(widths[i]);
2115 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2116 QCOMPARE(textObject->implicitHeight(), implicitHeight);
2117 QCOMPARE(textObject->width(), widths[i]);
2118 QCOMPARE(textObject->height(), implicitHeight);
2119 QCOMPARE(textObject->contentWidth(), implicitWidth);
2120 QCOMPARE(textObject->contentHeight(), implicitHeight);
2123 // With eliding enabled the content width is bounded to the item width, but is never
2124 // larger than the implicit width.
2125 textObject->setElideMode(QQuickText::ElideRight);
2126 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2127 QCOMPARE(textObject->implicitHeight(), implicitHeight);
2128 QCOMPARE(textObject->width(), 100.);
2129 QCOMPARE(textObject->height(), implicitHeight);
2130 QVERIFY(textObject->contentWidth() <= 100.);
2131 QCOMPARE(textObject->contentHeight(), implicitHeight);
2133 textObject->setWidth(2000.);
2134 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2135 QCOMPARE(textObject->implicitHeight(), implicitHeight);
2136 QCOMPARE(textObject->width(), 2000.);
2137 QCOMPARE(textObject->height(), implicitHeight);
2138 QCOMPARE(textObject->contentWidth(), implicitWidth);
2139 QCOMPARE(textObject->contentHeight(), implicitHeight);
2141 textObject->setWidth(3000.);
2142 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2143 QCOMPARE(textObject->implicitHeight(), implicitHeight);
2144 QCOMPARE(textObject->width(), 3000.);
2145 QCOMPARE(textObject->height(), implicitHeight);
2146 QCOMPARE(textObject->contentWidth(), implicitWidth);
2147 QCOMPARE(textObject->contentHeight(), implicitHeight);
2149 textObject->setWidth(-100);
2150 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2151 QCOMPARE(textObject->implicitHeight(), implicitHeight);
2152 QCOMPARE(textObject->width(), -100.);
2153 QCOMPARE(textObject->height(), implicitHeight);
2154 QCOMPARE(textObject->contentWidth(), 0.);
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 QVERIFY(textObject->contentWidth() <= 100.);
2163 QCOMPARE(textObject->contentHeight(), implicitHeight);
2165 // With wrapping enabled the implicit height changes with the width.
2166 textObject->setElideMode(QQuickText::ElideNone);
2167 textObject->setWrapMode(QQuickText::Wrap);
2168 const qreal wrappedImplicitHeight = textObject->implicitHeight();
2170 QVERIFY(wrappedImplicitHeight > implicitHeight);
2172 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2173 QCOMPARE(textObject->width(), 100.);
2174 QCOMPARE(textObject->height(), wrappedImplicitHeight);
2175 QVERIFY(textObject->contentWidth() <= 100.);
2176 QCOMPARE(textObject->contentHeight(), wrappedImplicitHeight);
2178 textObject->setWidth(2000.);
2179 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2180 QCOMPARE(textObject->implicitHeight(), implicitHeight);
2181 QCOMPARE(textObject->width(), 2000.);
2182 QCOMPARE(textObject->height(), implicitHeight);
2183 QCOMPARE(textObject->contentWidth(), implicitWidth);
2184 QCOMPARE(textObject->contentHeight(), implicitHeight);
2186 textObject->setWidth(3000.);
2187 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2188 QCOMPARE(textObject->implicitHeight(), implicitHeight);
2189 QCOMPARE(textObject->width(), 3000.);
2190 QCOMPARE(textObject->height(), implicitHeight);
2191 QCOMPARE(textObject->contentWidth(), implicitWidth);
2192 QCOMPARE(textObject->contentHeight(), implicitHeight);
2194 textObject->setWidth(-100);
2195 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2196 QCOMPARE(textObject->implicitHeight(), implicitHeight);
2197 QCOMPARE(textObject->width(), -100.);
2198 QCOMPARE(textObject->height(), implicitHeight);
2199 QCOMPARE(textObject->contentWidth(), implicitWidth); // 0 or negative width item won't wrap.
2200 QCOMPARE(textObject->contentHeight(), implicitHeight);
2202 textObject->setWidth(100.);
2203 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2204 QCOMPARE(textObject->implicitHeight(), wrappedImplicitHeight);
2205 QCOMPARE(textObject->width(), 100.);
2206 QCOMPARE(textObject->height(), wrappedImplicitHeight);
2207 QVERIFY(textObject->contentWidth() <= 100.);
2208 QCOMPARE(textObject->contentHeight(), wrappedImplicitHeight);
2210 // With no eliding or maximum line count the content height is the same as the implicit height.
2211 for (int i = 0; i < 5; ++i) {
2212 textObject->setHeight(heights[i]);
2213 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2214 QCOMPARE(textObject->implicitHeight(), wrappedImplicitHeight);
2215 QCOMPARE(textObject->width(), 100.);
2216 QCOMPARE(textObject->height(), heights[i]);
2217 QVERIFY(textObject->contentWidth() <= 100.);
2218 QCOMPARE(textObject->contentHeight(), wrappedImplicitHeight);
2221 // The implicit height is unaffected by eliding but the content height will change.
2222 textObject->setElideMode(QQuickText::ElideRight);
2224 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2225 QCOMPARE(textObject->implicitHeight(), wrappedImplicitHeight);
2226 QCOMPARE(textObject->width(), 100.);
2227 QCOMPARE(textObject->height(), implicitHeight);
2228 QVERIFY(textObject->contentWidth() <= 100.);
2229 QCOMPARE(textObject->contentHeight(), implicitHeight);
2231 textObject->setHeight(2000);
2232 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2233 QCOMPARE(textObject->implicitHeight(), wrappedImplicitHeight);
2234 QCOMPARE(textObject->width(), 100.);
2235 QCOMPARE(textObject->height(), 2000.);
2236 QVERIFY(textObject->contentWidth() <= 100.);
2237 QCOMPARE(textObject->contentHeight(), wrappedImplicitHeight);
2239 textObject->setHeight(3000);
2240 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2241 QCOMPARE(textObject->implicitHeight(), wrappedImplicitHeight);
2242 QCOMPARE(textObject->width(), 100.);
2243 QCOMPARE(textObject->height(), 3000.);
2244 QVERIFY(textObject->contentWidth() <= 100.);
2245 QCOMPARE(textObject->contentHeight(), wrappedImplicitHeight);
2247 textObject->setHeight(-implicitHeight);
2248 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2249 QCOMPARE(textObject->implicitHeight(), wrappedImplicitHeight);
2250 QCOMPARE(textObject->width(), 100.);
2251 QCOMPARE(textObject->height(), -implicitHeight);
2252 QVERIFY(textObject->contentWidth() <= 0.);
2253 QCOMPARE(textObject->contentHeight(), implicitHeight); // content height is never less than font height. seems a little odd in this instance.
2255 textObject->setHeight(implicitHeight);
2256 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2257 QCOMPARE(textObject->implicitHeight(), wrappedImplicitHeight);
2258 QCOMPARE(textObject->width(), 100.);
2259 QCOMPARE(textObject->height(), implicitHeight);
2260 QVERIFY(textObject->contentWidth() <= 100.);
2261 QCOMPARE(textObject->contentHeight(), implicitHeight);
2263 // Varying the height with a maximum line count but no eliding won't affect the content height.
2264 textObject->setElideMode(QQuickText::ElideNone);
2265 textObject->setMaximumLineCount(2);
2266 textObject->resetHeight();
2268 const qreal maxLineCountImplicitHeight = textObject->implicitHeight();
2269 QVERIFY(maxLineCountImplicitHeight > implicitHeight);
2270 QVERIFY(maxLineCountImplicitHeight < wrappedImplicitHeight);
2272 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2273 QCOMPARE(textObject->width(), 100.);
2274 QCOMPARE(textObject->height(), maxLineCountImplicitHeight);
2275 QVERIFY(textObject->contentWidth() <= 100.);
2276 QCOMPARE(textObject->contentHeight(), maxLineCountImplicitHeight);
2278 for (int i = 0; i < 5; ++i) {
2279 textObject->setHeight(heights[i]);
2280 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2281 QCOMPARE(textObject->implicitHeight(), maxLineCountImplicitHeight);
2282 QCOMPARE(textObject->width(), 100.);
2283 QCOMPARE(textObject->height(), heights[i]);
2284 QVERIFY(textObject->contentWidth() <= 100.);
2285 QCOMPARE(textObject->contentHeight(), maxLineCountImplicitHeight);
2288 // Varying the width with a maximum line count won't increase the implicit height beyond the
2289 // height of the maximum number of lines.
2290 textObject->setWidth(2000.);
2291 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2292 QCOMPARE(textObject->implicitHeight(), implicitHeight);
2293 QCOMPARE(textObject->width(), 2000.);
2294 QCOMPARE(textObject->height(), implicitHeight);
2295 QCOMPARE(textObject->contentWidth(), implicitWidth);
2296 QCOMPARE(textObject->contentHeight(), implicitHeight);
2298 textObject->setWidth(3000.);
2299 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2300 QCOMPARE(textObject->implicitHeight(), implicitHeight);
2301 QCOMPARE(textObject->width(), 3000.);
2302 QCOMPARE(textObject->height(), implicitHeight);
2303 QCOMPARE(textObject->contentWidth(), implicitWidth);
2304 QCOMPARE(textObject->contentHeight(), implicitHeight);
2306 textObject->setWidth(-100);
2307 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2308 QCOMPARE(textObject->implicitHeight(), implicitHeight);
2309 QCOMPARE(textObject->width(), -100.);
2310 QCOMPARE(textObject->height(), implicitHeight);
2311 QCOMPARE(textObject->contentWidth(), implicitWidth); // 0 or negative width item won't wrap.
2312 QCOMPARE(textObject->contentHeight(), implicitHeight);
2314 textObject->setWidth(50.);
2315 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2316 QCOMPARE(textObject->implicitHeight(), maxLineCountImplicitHeight);
2317 QCOMPARE(textObject->width(), 50.);
2318 QCOMPARE(textObject->height(), implicitHeight);
2319 QVERIFY(textObject->contentWidth() <= 50.);
2320 QCOMPARE(textObject->contentHeight(), maxLineCountImplicitHeight);
2322 textObject->setWidth(100.);
2323 QCOMPARE(textObject->implicitWidth(), implicitWidth);
2324 QCOMPARE(textObject->implicitHeight(), maxLineCountImplicitHeight);
2325 QCOMPARE(textObject->width(), 100.);
2326 QCOMPARE(textObject->height(), implicitHeight);
2327 QVERIFY(textObject->contentWidth() <= 100.);
2328 QCOMPARE(textObject->contentHeight(), maxLineCountImplicitHeight);
2331 void tst_qquicktext::implicitSizeBinding_data()
2333 implicitSize_data();
2336 void tst_qquicktext::implicitSizeBinding()
2338 QFETCH(QString, text);
2339 QFETCH(QString, wrap);
2340 QFETCH(QString, format);
2341 QString componentStr = "import QtQuick 2.0\nText { text: \"" + text + "\"; width: implicitWidth; height: implicitHeight; wrapMode: " + wrap + "; textFormat: " + format + " }";
2343 QQmlComponent textComponent(&engine);
2344 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
2345 QScopedPointer<QObject> object(textComponent.create());
2346 QQuickText *textObject = qobject_cast<QQuickText *>(object.data());
2348 QCOMPARE(textObject->width(), textObject->implicitWidth());
2349 QCOMPARE(textObject->height(), textObject->implicitHeight());
2351 textObject->resetWidth();
2352 QCOMPARE(textObject->width(), textObject->implicitWidth());
2353 QCOMPARE(textObject->height(), textObject->implicitHeight());
2355 textObject->resetHeight();
2356 QCOMPARE(textObject->width(), textObject->implicitWidth());
2357 QCOMPARE(textObject->height(), textObject->implicitHeight());
2360 void tst_qquicktext::boundingRect_data()
2362 QTest::addColumn<QString>("format");
2363 QTest::newRow("PlainText") << "Text.PlainText";
2364 QTest::newRow("StyledText") << "Text.StyledText";
2365 QTest::newRow("RichText") << "Text.RichText";
2368 void tst_qquicktext::boundingRect()
2370 QFETCH(QString, format);
2372 QQmlComponent component(&engine);
2373 component.setData("import QtQuick 2.0\n Text { textFormat:" + format.toUtf8() + "}", QUrl());
2374 QScopedPointer<QObject> object(component.create());
2375 QQuickText *text = qobject_cast<QQuickText *>(object.data());
2378 QCOMPARE(text->boundingRect().x(), qreal(0));
2379 QCOMPARE(text->boundingRect().y(), qreal(0));
2380 QCOMPARE(text->boundingRect().width(), qreal(0));
2381 QCOMPARE(text->boundingRect().height(), qreal(qCeil(QFontMetricsF(text->font()).height())));
2383 text->setText("Hello World");
2385 QTextLayout layout(text->text());
2386 layout.setFont(text->font());
2388 if (!qmlDisableDistanceField()) {
2390 option.setUseDesignMetrics(true);
2391 layout.setTextOption(option);
2393 layout.beginLayout();
2394 QTextLine line = layout.createLine();
2397 QCOMPARE(text->boundingRect().x(), qreal(0));
2398 QCOMPARE(text->boundingRect().y(), qreal(0));
2399 QCOMPARE(text->boundingRect().width(), line.naturalTextWidth());
2400 QCOMPARE(text->boundingRect().height(), line.height());
2402 // the size of the bounding rect shouldn't be bounded by the size of item.
2403 text->setWidth(text->width() / 2);
2404 QCOMPARE(text->boundingRect().x(), qreal(0));
2405 QCOMPARE(text->boundingRect().y(), qreal(0));
2406 QCOMPARE(text->boundingRect().width(), line.naturalTextWidth());
2407 QCOMPARE(text->boundingRect().height(), line.height());
2409 text->setHeight(text->height() * 2);
2410 QCOMPARE(text->boundingRect().x(), qreal(0));
2411 QCOMPARE(text->boundingRect().y(), qreal(0));
2412 QCOMPARE(text->boundingRect().width(), line.naturalTextWidth());
2413 QCOMPARE(text->boundingRect().height(), line.height());
2415 text->setHAlign(QQuickText::AlignRight);
2416 QCOMPARE(text->boundingRect().x(), text->width() - line.naturalTextWidth());
2417 QCOMPARE(text->boundingRect().y(), qreal(0));
2418 QCOMPARE(text->boundingRect().width(), line.naturalTextWidth());
2419 QCOMPARE(text->boundingRect().height(), line.height());
2421 text->setWrapMode(QQuickText::Wrap);
2422 QCOMPARE(text->boundingRect().right(), text->width());
2423 QCOMPARE(text->boundingRect().y(), qreal(0));
2424 QVERIFY(text->boundingRect().width() < line.naturalTextWidth());
2425 QVERIFY(text->boundingRect().height() > line.height());
2427 text->setVAlign(QQuickText::AlignBottom);
2428 QCOMPARE(text->boundingRect().right(), text->width());
2429 QCOMPARE(text->boundingRect().bottom(), text->height());
2430 QVERIFY(text->boundingRect().width() < line.naturalTextWidth());
2431 QVERIFY(text->boundingRect().height() > line.height());
2434 void tst_qquicktext::clipRect()
2436 QQmlComponent component(&engine);
2437 component.setData("import QtQuick 2.0\n Text {}", QUrl());
2438 QScopedPointer<QObject> object(component.create());
2439 QQuickText *text = qobject_cast<QQuickText *>(object.data());
2443 layout.setFont(text->font());
2445 QCOMPARE(text->clipRect().x(), qreal(0));
2446 QCOMPARE(text->clipRect().y(), qreal(0));
2447 QCOMPARE(text->clipRect().width(), text->width());
2448 QCOMPARE(text->clipRect().height(), text->height());
2450 text->setText("Hello World");
2452 QCOMPARE(text->clipRect().x(), qreal(0));
2453 QCOMPARE(text->clipRect().y(), qreal(0));
2454 QCOMPARE(text->clipRect().width(), text->width());
2455 QCOMPARE(text->clipRect().height(), text->height());
2457 // Clip rect follows the item not content dimensions.
2458 text->setWidth(text->width() / 2);
2459 QCOMPARE(text->clipRect().x(), qreal(0));
2460 QCOMPARE(text->clipRect().y(), qreal(0));
2461 QCOMPARE(text->clipRect().width(), text->width());
2462 QCOMPARE(text->clipRect().height(), text->height());
2464 text->setHeight(text->height() * 2);
2465 QCOMPARE(text->clipRect().x(), qreal(0));
2466 QCOMPARE(text->clipRect().y(), qreal(0));
2467 QCOMPARE(text->clipRect().width(), text->width());
2468 QCOMPARE(text->clipRect().height(), text->height());
2470 // Setting a style adds a small amount of padding to the clip rect.
2471 text->setStyle(QQuickText::Outline);
2472 QCOMPARE(text->clipRect().x(), qreal(-1));
2473 QCOMPARE(text->clipRect().y(), qreal(0));
2474 QCOMPARE(text->clipRect().width(), text->width() + 2);
2475 QCOMPARE(text->clipRect().height(), text->height() + 2);
2478 void tst_qquicktext::lineLaidOut()
2480 QQuickView *window = createView(testFile("lineLayout.qml"));
2482 QQuickText *myText = window->rootObject()->findChild<QQuickText*>("myText");
2483 QVERIFY(myText != 0);
2485 QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(myText);
2486 QVERIFY(textPrivate != 0);
2488 QVERIFY(!textPrivate->extra.isAllocated());
2490 for (int i = 0; i < textPrivate->layout.lineCount(); ++i) {
2491 QRectF r = textPrivate->layout.lineAt(i).rect();
2492 QVERIFY(r.width() == i * 15);
2494 QVERIFY(r.x() == r.width() + 30);
2496 QVERIFY(r.x() == r.width() * 2 + 60);
2497 QVERIFY(r.height() == 20);
2504 void tst_qquicktext::lineLaidOutRelayout()
2506 QQuickView *window = createView(testFile("lineLayoutRelayout.qml"));
2509 window->requestActivate();
2510 QVERIFY(QTest::qWaitForWindowActive(window));
2512 QQuickText *myText = window->rootObject()->findChild<QQuickText*>("myText");
2513 QVERIFY(myText != 0);
2515 QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(myText);
2516 QVERIFY(textPrivate != 0);
2518 QVERIFY(!textPrivate->extra.isAllocated());
2521 for (int i = 0; i < textPrivate->layout.lineCount(); ++i) {
2522 QRectF r = textPrivate->layout.lineAt(i).rect();
2525 QCOMPARE(r.y(), i * r.height());
2526 maxH = qMax(maxH, r.y() + r.height());
2528 QCOMPARE(r.x(), myText->width() / 2);
2529 QCOMPARE(r.y(), (i * r.height()) - maxH);
2536 void tst_qquicktext::imgTagsBaseUrl_data()
2538 QTest::addColumn<QUrl>("src");
2539 QTest::addColumn<QUrl>("baseUrl");
2540 QTest::addColumn<QUrl>("contextUrl");
2541 QTest::addColumn<qreal>("imgHeight");
2543 QTest::newRow("absolute local")
2544 << testFileUrl("images/heart200.png")
2548 QTest::newRow("relative local context 1")
2549 << QUrl("images/heart200.png")
2551 << testFileUrl("/app.qml")
2553 QTest::newRow("relative local context 2")
2554 << QUrl("heart200.png")
2556 << testFileUrl("images/app.qml")
2558 QTest::newRow("relative local base 1")
2559 << QUrl("images/heart200.png")
2561 << testFileUrl("nonexistant/app.qml")
2563 QTest::newRow("relative local base 2")
2564 << QUrl("heart200.png")
2565 << testFileUrl("images/")
2566 << testFileUrl("nonexistant/app.qml")
2568 QTest::newRow("base relative to local context")
2569 << QUrl("heart200.png")
2570 << testFileUrl("images/")
2571 << testFileUrl("/app.qml")
2574 QTest::newRow("absolute remote")
2575 << QUrl(SERVER_ADDR "/images/heart200.png")
2579 QTest::newRow("relative remote base 1")
2580 << QUrl("images/heart200.png")
2581 << QUrl(SERVER_ADDR "/")
2582 << testFileUrl("nonexistant/app.qml")
2584 QTest::newRow("relative remote base 2")
2585 << QUrl("heart200.png")
2586 << QUrl(SERVER_ADDR "/images/")
2587 << testFileUrl("nonexistant/app.qml")
2591 void tst_qquicktext::imgTagsBaseUrl()
2594 QFETCH(QUrl, baseUrl);
2595 QFETCH(QUrl, contextUrl);
2596 QFETCH(qreal, imgHeight);
2598 TestHTTPServer server(SERVER_PORT);
2599 server.serveDirectory(testFile(""));
2601 QByteArray baseUrlFragment;
2602 if (!baseUrl.isEmpty())
2603 baseUrlFragment = "; baseUrl: \"" + baseUrl.toEncoded() + "\"";
2604 QByteArray componentStr = "import QtQuick 2.0\nText { text: \"This is a test <img src=\\\"" + src.toEncoded() + "\\\">\"" + baseUrlFragment + " }";
2606 QQmlComponent component(&engine);
2607 component.setData(componentStr, contextUrl);
2608 QScopedPointer<QObject> object(component.create());
2609 QQuickText *textObject = qobject_cast<QQuickText *>(object.data());
2610 QVERIFY(textObject);
2612 QCoreApplication::processEvents();
2614 QTRY_COMPARE(textObject->height(), imgHeight);
2617 void tst_qquicktext::imgTagsAlign_data()
2619 QTest::addColumn<QString>("src");
2620 QTest::addColumn<int>("imgHeight");
2621 QTest::addColumn<QString>("align");
2622 QTest::newRow("heart-bottom") << "data/images/heart200.png" << 181 << "bottom";
2623 QTest::newRow("heart-middle") << "data/images/heart200.png" << 181 << "middle";
2624 QTest::newRow("heart-top") << "data/images/heart200.png" << 181 << "top";
2625 QTest::newRow("starfish-bottom") << "data/images/starfish_2.png" << 217 << "bottom";
2626 QTest::newRow("starfish-middle") << "data/images/starfish_2.png" << 217 << "middle";
2627 QTest::newRow("starfish-top") << "data/images/starfish_2.png" << 217 << "top";
2630 void tst_qquicktext::imgTagsAlign()
2632 QFETCH(QString, src);
2633 QFETCH(int, imgHeight);
2634 QFETCH(QString, align);
2635 QString componentStr = "import QtQuick 2.0\nText { text: \"This is a test <img src=\\\"" + src + "\\\" align=\\\"" + align + "\\\"> of image.\" }";
2636 QQmlComponent textComponent(&engine);
2637 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
2638 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
2640 QVERIFY(textObject != 0);
2641 QVERIFY(textObject->height() == imgHeight);
2643 QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject);
2644 QVERIFY(textPrivate != 0);
2646 QRectF br = textPrivate->layout.boundingRect();
2647 if (align == "bottom")
2648 QVERIFY(br.y() == imgHeight - br.height());
2649 else if (align == "middle")
2650 QVERIFY(br.y() == imgHeight / 2.0 - br.height() / 2.0);
2651 else if (align == "top")
2652 QVERIFY(br.y() == 0);
2657 void tst_qquicktext::imgTagsMultipleImages()
2659 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\\\">.\" }";
2661 QQmlComponent textComponent(&engine);
2662 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
2663 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
2665 QVERIFY(textObject != 0);
2666 QVERIFY(textObject->height() == 85);
2668 QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject);
2669 QVERIFY(textPrivate != 0);
2670 QVERIFY(textPrivate->visibleImgTags.count() == 2);
2675 void tst_qquicktext::imgTagsElide()
2677 QQuickView *window = createView(testFile("imgTagsElide.qml"));
2678 QQuickText *myText = window->rootObject()->findChild<QQuickText*>("myText");
2679 QVERIFY(myText != 0);
2681 QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(myText);
2682 QVERIFY(textPrivate != 0);
2683 QVERIFY(textPrivate->visibleImgTags.count() == 0);
2684 myText->setMaximumLineCount(20);
2685 QTRY_VERIFY(textPrivate->visibleImgTags.count() == 1);
2691 void tst_qquicktext::imgTagsUpdates()
2693 QQuickView *window = createView(testFile("imgTagsUpdates.qml"));
2694 QQuickText *myText = window->rootObject()->findChild<QQuickText*>("myText");
2695 QVERIFY(myText != 0);
2697 QSignalSpy spy(myText, SIGNAL(contentSizeChanged()));
2699 QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(myText);
2700 QVERIFY(textPrivate != 0);
2702 myText->setText("This is a heart<img src=\"images/heart200.png\">.");
2703 QVERIFY(textPrivate->visibleImgTags.count() == 1);
2704 QVERIFY(spy.count() == 1);
2706 myText->setMaximumLineCount(2);
2707 myText->setText("This is another heart<img src=\"images/heart200.png\">.");
2708 QTRY_VERIFY(textPrivate->visibleImgTags.count() == 1);
2710 // if maximumLineCount is set and the img tag doesn't have an explicit size
2711 // we relayout twice.
2712 QVERIFY(spy.count() == 3);
2718 void tst_qquicktext::imgTagsError()
2720 QString componentStr = "import QtQuick 2.0\nText { text: \"This is a starfish<img src=\\\"data/images/starfish_2.pn\\\" width=\\\"60\\\" height=\\\"60\\\">.\" }";
2722 QQmlComponent textComponent(&engine);
2723 QTest::ignoreMessage(QtWarningMsg, "file::2:1: QML Text: Cannot open: file:data/images/starfish_2.pn");
2724 textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
2725 QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
2727 QVERIFY(textObject != 0);
2731 void tst_qquicktext::fontSizeMode_data()
2733 QTest::addColumn<QString>("text");
2734 QTest::newRow("plain") << "The quick red fox jumped over the lazy brown dog";
2735 QTest::newRow("styled") << "<b>The quick red fox jumped over the lazy brown dog</b>";
2738 void tst_qquicktext::fontSizeMode()
2740 QFETCH(QString, text);
2742 QScopedPointer<QQuickView> window(createView(testFile("fontSizeMode.qml")));
2745 QQuickText *myText = window->rootObject()->findChild<QQuickText*>("myText");
2746 QVERIFY(myText != 0);
2748 myText->setText(text);
2749 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2751 qreal originalWidth = myText->contentWidth();
2752 qreal originalHeight = myText->contentHeight();
2754 // The original text unwrapped should exceed the width of the item.
2755 QVERIFY(originalWidth > myText->width());
2756 QVERIFY(originalHeight < myText->height());
2758 QFont font = myText->font();
2759 font.setPixelSize(64);
2761 myText->setFont(font);
2762 myText->setFontSizeMode(QQuickText::HorizontalFit);
2763 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2764 // Font size reduced to fit within the width of the item.
2765 qreal horizontalFitWidth = myText->contentWidth();
2766 qreal horizontalFitHeight = myText->contentHeight();
2767 QVERIFY(horizontalFitWidth <= myText->width() + 2); // rounding
2768 QVERIFY(horizontalFitHeight <= myText->height() + 2);
2770 // Elide won't affect the size with HorizontalFit.
2771 myText->setElideMode(QQuickText::ElideRight);
2772 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2773 QVERIFY(!myText->truncated());
2774 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2775 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2777 myText->setElideMode(QQuickText::ElideLeft);
2778 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2779 QVERIFY(!myText->truncated());
2780 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2781 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2783 myText->setElideMode(QQuickText::ElideMiddle);
2784 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2785 QVERIFY(!myText->truncated());
2786 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2787 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2789 myText->setElideMode(QQuickText::ElideNone);
2790 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2792 myText->setFontSizeMode(QQuickText::VerticalFit);
2793 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2794 // Font size increased to fill the height of the item.
2795 qreal verticalFitHeight = myText->contentHeight();
2796 QVERIFY(myText->contentWidth() > myText->width());
2797 QVERIFY(verticalFitHeight <= myText->height() + 2);
2798 QVERIFY(verticalFitHeight > originalHeight);
2800 // Elide won't affect the height of a single line with VerticalFit but will crop the width.
2801 myText->setElideMode(QQuickText::ElideRight);
2802 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2803 QVERIFY(myText->truncated());
2804 QVERIFY(myText->contentWidth() <= myText->width() + 2);
2805 QCOMPARE(myText->contentHeight(), verticalFitHeight);
2807 myText->setElideMode(QQuickText::ElideLeft);
2808 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2809 QVERIFY(myText->truncated());
2810 QVERIFY(myText->contentWidth() <= myText->width() + 2);
2811 QCOMPARE(myText->contentHeight(), verticalFitHeight);
2813 myText->setElideMode(QQuickText::ElideMiddle);
2814 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2815 QVERIFY(myText->truncated());
2816 QVERIFY(myText->contentWidth() <= myText->width() + 2);
2817 QCOMPARE(myText->contentHeight(), verticalFitHeight);
2819 myText->setElideMode(QQuickText::ElideNone);
2820 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2822 myText->setFontSizeMode(QQuickText::Fit);
2823 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2824 // Should be the same as HorizontalFit with no wrapping.
2825 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2826 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2828 // Elide won't affect the size with Fit.
2829 myText->setElideMode(QQuickText::ElideRight);
2830 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2831 QVERIFY(!myText->truncated());
2832 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2833 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2835 myText->setElideMode(QQuickText::ElideLeft);
2836 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2837 QVERIFY(!myText->truncated());
2838 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2839 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2841 myText->setElideMode(QQuickText::ElideMiddle);
2842 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2843 QVERIFY(!myText->truncated());
2844 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2845 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2847 myText->setElideMode(QQuickText::ElideNone);
2848 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2850 myText->setFontSizeMode(QQuickText::FixedSize);
2851 myText->setWrapMode(QQuickText::Wrap);
2852 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2854 originalWidth = myText->contentWidth();
2855 originalHeight = myText->contentHeight();
2857 // The original text wrapped should exceed the height of the item.
2858 QVERIFY(originalWidth <= myText->width() + 2);
2859 QVERIFY(originalHeight > myText->height());
2861 myText->setFontSizeMode(QQuickText::HorizontalFit);
2862 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2863 // HorizontalFit should reduce the font size to minimize wrapping, which brings it back to the
2864 // same size as without text wrapping.
2865 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2866 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2868 // Elide won't affect the size with HorizontalFit.
2869 myText->setElideMode(QQuickText::ElideRight);
2870 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2871 QVERIFY(!myText->truncated());
2872 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2873 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2875 myText->setElideMode(QQuickText::ElideNone);
2876 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2878 myText->setFontSizeMode(QQuickText::VerticalFit);
2879 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2880 // VerticalFit should reduce the size to the wrapped text within the vertical height.
2881 verticalFitHeight = myText->contentHeight();
2882 qreal verticalFitWidth = myText->contentWidth();
2883 QVERIFY(myText->contentWidth() <= myText->width() + 2);
2884 QVERIFY(verticalFitHeight <= myText->height() + 2);
2885 QVERIFY(verticalFitHeight < originalHeight);
2887 // Elide won't affect the height or width of a wrapped text with VerticalFit.
2888 myText->setElideMode(QQuickText::ElideRight);
2889 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2890 QVERIFY(!myText->truncated());
2891 QCOMPARE(myText->contentWidth(), verticalFitWidth);
2892 QCOMPARE(myText->contentHeight(), verticalFitHeight);
2894 myText->setElideMode(QQuickText::ElideNone);
2895 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2897 myText->setFontSizeMode(QQuickText::Fit);
2898 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2899 // Should be the same as VerticalFit with wrapping.
2900 QCOMPARE(myText->contentWidth(), verticalFitWidth);
2901 QCOMPARE(myText->contentHeight(), verticalFitHeight);
2903 // Elide won't affect the size with Fit.
2904 myText->setElideMode(QQuickText::ElideRight);
2905 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2906 QVERIFY(!myText->truncated());
2907 QCOMPARE(myText->contentWidth(), verticalFitWidth);
2908 QCOMPARE(myText->contentHeight(), verticalFitHeight);
2910 myText->setElideMode(QQuickText::ElideNone);
2911 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2913 myText->setFontSizeMode(QQuickText::FixedSize);
2914 myText->setMaximumLineCount(2);
2915 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2917 // The original text wrapped should exceed the height of the item.
2918 QVERIFY(originalWidth <= myText->width() + 2);
2919 QVERIFY(originalHeight > myText->height());
2921 myText->setFontSizeMode(QQuickText::HorizontalFit);
2922 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2923 // HorizontalFit should reduce the font size to minimize wrapping, which brings it back to the
2924 // same size as without text wrapping.
2925 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2926 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2928 // Elide won't affect the size with HorizontalFit.
2929 myText->setElideMode(QQuickText::ElideRight);
2930 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2931 QVERIFY(!myText->truncated());
2932 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2933 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2935 myText->setElideMode(QQuickText::ElideNone);
2936 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2938 myText->setFontSizeMode(QQuickText::VerticalFit);
2939 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2940 // VerticalFit should reduce the size to the wrapped text within the vertical height.
2941 verticalFitHeight = myText->contentHeight();
2942 verticalFitWidth = myText->contentWidth();
2943 QVERIFY(myText->contentWidth() <= myText->width() + 2);
2944 QVERIFY(verticalFitHeight <= myText->height() + 2);
2945 QVERIFY(verticalFitHeight < originalHeight);
2947 // Elide won't affect the height or width of a wrapped text with VerticalFit.
2948 myText->setElideMode(QQuickText::ElideRight);
2949 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2950 QVERIFY(!myText->truncated());
2951 QCOMPARE(myText->contentWidth(), verticalFitWidth);
2952 QCOMPARE(myText->contentHeight(), verticalFitHeight);
2954 myText->setElideMode(QQuickText::ElideNone);
2955 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2957 myText->setFontSizeMode(QQuickText::Fit);
2958 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2959 // Should be the same as VerticalFit with wrapping.
2960 QCOMPARE(myText->contentWidth(), verticalFitWidth);
2961 QCOMPARE(myText->contentHeight(), verticalFitHeight);
2963 // Elide won't affect the size with Fit.
2964 myText->setElideMode(QQuickText::ElideRight);
2965 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2966 QVERIFY(!myText->truncated());
2967 QCOMPARE(myText->contentWidth(), verticalFitWidth);
2968 QCOMPARE(myText->contentHeight(), verticalFitHeight);
2970 myText->setElideMode(QQuickText::ElideNone);
2971 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2974 void tst_qquicktext::fontSizeModeMultiline_data()
2976 QTest::addColumn<QString>("text");
2977 QTest::newRow("plain") << "The quick red fox jumped\n over the lazy brown dog";
2978 QTest::newRow("styledtext") << "<b>The quick red fox jumped<br/> over the lazy brown dog</b>";
2981 void tst_qquicktext::fontSizeModeMultiline()
2983 QFETCH(QString, text);
2985 QScopedPointer<QQuickView> window(createView(testFile("fontSizeMode.qml")));
2988 QQuickText *myText = window->rootObject()->findChild<QQuickText*>("myText");
2989 QVERIFY(myText != 0);
2991 myText->setText(text);
2992 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2994 qreal originalWidth = myText->contentWidth();
2995 qreal originalHeight = myText->contentHeight();
2996 QCOMPARE(myText->lineCount(), 2);
2998 // The original text unwrapped should exceed the width and height of the item.
2999 QVERIFY(originalWidth > myText->width());
3000 QVERIFY(originalHeight > myText->height());
3002 QFont font = myText->font();
3003 font.setPixelSize(64);
3005 myText->setFont(font);
3006 myText->setFontSizeMode(QQuickText::HorizontalFit);
3007 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3008 // Font size reduced to fit within the width of the item.
3009 QCOMPARE(myText->lineCount(), 2);
3010 qreal horizontalFitWidth = myText->contentWidth();
3011 qreal horizontalFitHeight = myText->contentHeight();
3012 QVERIFY(horizontalFitWidth <= myText->width() + 2); // rounding
3013 QVERIFY(horizontalFitHeight > myText->height());
3015 // Right eliding will remove the last line
3016 myText->setElideMode(QQuickText::ElideRight);
3017 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3018 QVERIFY(myText->truncated());
3019 QCOMPARE(myText->lineCount(), 1);
3020 QVERIFY(myText->contentWidth() <= myText->width() + 2);
3021 QVERIFY(myText->contentHeight() <= myText->height() + 2);
3023 // Left or middle eliding wont have any effect.
3024 myText->setElideMode(QQuickText::ElideLeft);
3025 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3026 QVERIFY(!myText->truncated());
3027 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
3028 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
3030 myText->setElideMode(QQuickText::ElideMiddle);
3031 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3032 QVERIFY(!myText->truncated());
3033 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
3034 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
3036 myText->setElideMode(QQuickText::ElideNone);
3037 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3039 myText->setFontSizeMode(QQuickText::VerticalFit);
3040 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3041 // Font size reduced to fit within the height of the item.
3042 qreal verticalFitWidth = myText->contentWidth();
3043 qreal verticalFitHeight = myText->contentHeight();
3044 QVERIFY(verticalFitWidth <= myText->width() + 2);
3045 QVERIFY(verticalFitHeight <= myText->height() + 2);
3047 // Elide will have no effect.
3048 myText->setElideMode(QQuickText::ElideRight);
3049 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3050 QVERIFY(!myText->truncated());
3051 QVERIFY(myText->contentWidth() <= myText->width() + 2);
3052 QCOMPARE(myText->contentWidth(), verticalFitWidth);
3053 QCOMPARE(myText->contentHeight(), verticalFitHeight);
3055 myText->setElideMode(QQuickText::ElideLeft);
3056 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3057 QVERIFY(!myText->truncated());
3058 QCOMPARE(myText->contentWidth(), verticalFitWidth);
3059 QCOMPARE(myText->contentHeight(), verticalFitHeight);
3061 myText->setElideMode(QQuickText::ElideMiddle);
3062 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3063 QVERIFY(!myText->truncated());
3064 QCOMPARE(myText->contentWidth(), verticalFitWidth);
3065 QCOMPARE(myText->contentHeight(), verticalFitHeight);
3067 myText->setElideMode(QQuickText::ElideNone);
3068 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3070 myText->setFontSizeMode(QQuickText::Fit);
3071 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3072 // Should be the same as VerticalFit with no wrapping.
3073 QCOMPARE(myText->contentWidth(), verticalFitWidth);
3074 QCOMPARE(myText->contentHeight(), verticalFitHeight);
3076 // Elide won't affect the size with Fit.
3077 myText->setElideMode(QQuickText::ElideRight);
3078 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3079 QVERIFY(!myText->truncated());
3080 QCOMPARE(myText->contentWidth(), verticalFitWidth);
3081 QCOMPARE(myText->contentHeight(), verticalFitHeight);
3083 myText->setElideMode(QQuickText::ElideLeft);
3084 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3085 QVERIFY(!myText->truncated());
3086 QCOMPARE(myText->contentWidth(), verticalFitWidth);
3087 QCOMPARE(myText->contentHeight(), verticalFitHeight);
3089 myText->setElideMode(QQuickText::ElideMiddle);
3090 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3091 QVERIFY(!myText->truncated());
3092 QCOMPARE(myText->contentWidth(), verticalFitWidth);
3093 QCOMPARE(myText->contentHeight(), verticalFitHeight);
3095 myText->setElideMode(QQuickText::ElideNone);
3096 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3098 myText->setFontSizeMode(QQuickText::FixedSize);
3099 myText->setWrapMode(QQuickText::Wrap);
3100 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3102 originalWidth = myText->contentWidth();
3103 originalHeight = myText->contentHeight();
3105 // The original text wrapped should exceed the height of the item.
3106 QVERIFY(originalWidth <= myText->width() + 2);
3107 QVERIFY(originalHeight > myText->height());
3109 myText->setFontSizeMode(QQuickText::HorizontalFit);
3110 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3111 // HorizontalFit should reduce the font size to minimize wrapping, which brings it back to the
3112 // same size as without text wrapping.
3113 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
3114 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
3116 // Text will be elided vertically with HorizontalFit
3117 myText->setElideMode(QQuickText::ElideRight);
3118 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3119 QVERIFY(myText->truncated());
3120 QVERIFY(myText->contentWidth() <= myText->width() + 2);
3121 QVERIFY(myText->contentHeight() <= myText->height() + 2);
3123 myText->setElideMode(QQuickText::ElideNone);
3124 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3126 myText->setFontSizeMode(QQuickText::VerticalFit);
3127 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3128 // VerticalFit should reduce the size to the wrapped text within the vertical height.
3129 verticalFitHeight = myText->contentHeight();
3130 verticalFitWidth = myText->contentWidth();
3131 QVERIFY(myText->contentWidth() <= myText->width() + 2);
3132 QVERIFY(verticalFitHeight <= myText->height() + 2);
3133 QVERIFY(verticalFitHeight < originalHeight);
3135 // Elide won't affect the height or width of a wrapped text with VerticalFit.
3136 myText->setElideMode(QQuickText::ElideRight);
3137 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3138 QVERIFY(!myText->truncated());
3139 QCOMPARE(myText->contentWidth(), verticalFitWidth);
3140 QCOMPARE(myText->contentHeight(), verticalFitHeight);
3142 myText->setElideMode(QQuickText::ElideNone);
3143 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3145 myText->setFontSizeMode(QQuickText::Fit);
3146 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3147 // Should be the same as VerticalFit with wrapping.
3148 QCOMPARE(myText->contentWidth(), verticalFitWidth);
3149 QCOMPARE(myText->contentHeight(), verticalFitHeight);
3151 // Elide won't affect the size with Fit.
3152 myText->setElideMode(QQuickText::ElideRight);
3153 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3154 QVERIFY(!myText->truncated());
3155 QCOMPARE(myText->contentWidth(), verticalFitWidth);
3156 QCOMPARE(myText->contentHeight(), verticalFitHeight);
3158 myText->setElideMode(QQuickText::ElideNone);
3159 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3161 myText->setFontSizeMode(QQuickText::FixedSize);
3162 myText->setMaximumLineCount(2);
3163 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3165 // The original text wrapped should exceed the height of the item.
3166 QVERIFY(originalWidth <= myText->width() + 2);
3167 QVERIFY(originalHeight > myText->height());
3169 myText->setFontSizeMode(QQuickText::HorizontalFit);
3170 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3171 // HorizontalFit should reduce the font size to minimize wrapping, which brings it back to the
3172 // same size as without text wrapping.
3173 QCOMPARE(myText->contentWidth(), horizontalFitWidth);
3174 QCOMPARE(myText->contentHeight(), horizontalFitHeight);
3176 // Elide won't affect the size with HorizontalFit.
3177 myText->setElideMode(QQuickText::ElideRight);
3178 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3179 QVERIFY(myText->truncated());
3180 QVERIFY(myText->contentWidth() <= myText->width() + 2);
3181 QVERIFY(myText->contentHeight() <= myText->height() + 2);
3183 myText->setElideMode(QQuickText::ElideNone);
3184 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3186 myText->setFontSizeMode(QQuickText::VerticalFit);
3187 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3188 // VerticalFit should reduce the size to the wrapped text within the vertical height.
3189 verticalFitHeight = myText->contentHeight();
3190 verticalFitWidth = myText->contentWidth();
3191 QVERIFY(myText->contentWidth() <= myText->width() + 2);
3192 QVERIFY(verticalFitHeight <= myText->height() + 2);
3193 QVERIFY(verticalFitHeight < originalHeight);
3195 // Elide won't affect the height or width of a wrapped text with VerticalFit.
3196 myText->setElideMode(QQuickText::ElideRight);
3197 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3198 QVERIFY(!myText->truncated());
3199 QCOMPARE(myText->contentWidth(), verticalFitWidth);
3200 QCOMPARE(myText->contentHeight(), verticalFitHeight);
3202 myText->setElideMode(QQuickText::ElideNone);
3203 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3205 myText->setFontSizeMode(QQuickText::Fit);
3206 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3207 // Should be the same as VerticalFit with wrapping.
3208 QCOMPARE(myText->contentWidth(), verticalFitWidth);
3209 QCOMPARE(myText->contentHeight(), verticalFitHeight);
3211 // Elide won't affect the size with Fit.
3212 myText->setElideMode(QQuickText::ElideRight);
3213 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3214 QVERIFY(!myText->truncated());
3215 QCOMPARE(myText->contentWidth(), verticalFitWidth);
3216 QCOMPARE(myText->contentHeight(), verticalFitHeight);
3218 myText->setElideMode(QQuickText::ElideNone);
3219 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3222 void tst_qquicktext::multilengthStrings_data()
3224 QTest::addColumn<QString>("source");
3225 QTest::newRow("No Wrap") << testFile("multilengthStrings.qml");
3226 QTest::newRow("Wrap") << testFile("multilengthStringsWrapped.qml");
3229 void tst_qquicktext::multilengthStrings()
3231 QFETCH(QString, source);
3233 QScopedPointer<QQuickView> window(createView(source));
3236 QQuickText *myText = window->rootObject()->findChild<QQuickText*>("myText");
3237 QVERIFY(myText != 0);
3239 const QString longText = "the quick brown fox jumped over the lazy dog";
3240 const QString mediumText = "the brown fox jumped over the dog";
3241 const QString shortText = "fox jumped dog";
3243 myText->setText(longText);
3244 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3245 const qreal longWidth = myText->contentWidth();
3246 const qreal longHeight = myText->contentHeight();
3248 myText->setText(mediumText);
3249 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3250 const qreal mediumWidth = myText->contentWidth();
3251 const qreal mediumHeight = myText->contentHeight();
3253 myText->setText(shortText);
3254 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3255 const qreal shortWidth = myText->contentWidth();
3256 const qreal shortHeight = myText->contentHeight();
3258 myText->setElideMode(QQuickText::ElideRight);
3259 myText->setText(longText + QLatin1Char('\x9c') + mediumText + QLatin1Char('\x9c') + shortText);
3261 myText->setSize(QSizeF(longWidth, longHeight));
3262 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3264 QCOMPARE(myText->contentWidth(), longWidth);
3265 QCOMPARE(myText->contentHeight(), longHeight);
3266 QCOMPARE(myText->truncated(), false);
3268 myText->setSize(QSizeF(mediumWidth, mediumHeight));
3269 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3271 QCOMPARE(myText->contentWidth(), mediumWidth);
3272 QCOMPARE(myText->contentHeight(), mediumHeight);
3273 QCOMPARE(myText->truncated(), true);
3275 myText->setSize(QSizeF(shortWidth, shortHeight));
3276 QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
3278 QCOMPARE(myText->contentWidth(), shortWidth);
3279 QCOMPARE(myText->contentHeight(), shortHeight);
3280 QCOMPARE(myText->truncated(), true);
3283 void tst_qquicktext::fontFormatSizes_data()
3285 QTest::addColumn<QString>("text");
3286 QTest::addColumn<QString>("textWithTag");
3287 QTest::addColumn<bool>("fontIsBigger");
3289 QTest::newRow("fs1") << "Hello world!" << "Hello <font size=\"1\">world</font>!" << false;
3290 QTest::newRow("fs2") << "Hello world!" << "Hello <font size=\"2\">world</font>!" << false;
3291 QTest::newRow("fs3") << "Hello world!" << "Hello <font size=\"3\">world</font>!" << false;
3292 QTest::newRow("fs4") << "Hello world!" << "Hello <font size=\"4\">world</font>!" << true;
3293 QTest::newRow("fs5") << "Hello world!" << "Hello <font size=\"5\">world</font>!" << true;
3294 QTest::newRow("fs6") << "Hello world!" << "Hello <font size=\"6\">world</font>!" << true;
3295 QTest::newRow("fs7") << "Hello world!" << "Hello <font size=\"7\">world</font>!" << true;
3296 QTest::newRow("h1") << "This is<br/>a font<br/> size test." << "This is <h1>a font</h1> size test." << true;
3297 QTest::newRow("h2") << "This is<br/>a font<br/> size test." << "This is <h2>a font</h2> size test." << true;
3298 QTest::newRow("h3") << "This is<br/>a font<br/> size test." << "This is <h3>a font</h3> size test." << true;
3299 QTest::newRow("h4") << "This is<br/>a font<br/> size test." << "This is <h4>a font</h4> size test." << true;
3300 QTest::newRow("h5") << "This is<br/>a font<br/> size test." << "This is <h5>a font</h5> size test." << false;
3301 QTest::newRow("h6") << "This is<br/>a font<br/> size test." << "This is <h6>a font</h6> size test." << false;
3304 void tst_qquicktext::fontFormatSizes()
3306 QFETCH(QString, text);
3307 QFETCH(QString, textWithTag);
3308 QFETCH(bool, fontIsBigger);
3310 QQuickView *view = new QQuickView;
3312 view->setSource(testFileUrl("pointFontSizes.qml"));
3315 QQuickText *qtext = view->rootObject()->findChild<QQuickText*>("text");
3316 QQuickText *qtextWithTag = view->rootObject()->findChild<QQuickText*>("textWithTag");
3317 QVERIFY(qtext != 0);
3318 QVERIFY(qtextWithTag != 0);
3320 qtext->setText(text);
3321 qtextWithTag->setText(textWithTag);
3323 for (int size = 6; size < 100; size += 4) {
3324 view->rootObject()->setProperty("pointSize", size);
3326 QVERIFY(qtext->height() <= qtextWithTag->height());
3328 QVERIFY(qtext->height() >= qtextWithTag->height());
3333 view->setSource(testFileUrl("pixelFontSizes.qml"));
3334 QQuickText *qtext = view->rootObject()->findChild<QQuickText*>("text");
3335 QQuickText *qtextWithTag = view->rootObject()->findChild<QQuickText*>("textWithTag");
3336 QVERIFY(qtext != 0);
3337 QVERIFY(qtextWithTag != 0);
3339 qtext->setText(text);
3340 qtextWithTag->setText(textWithTag);
3342 for (int size = 6; size < 100; size += 4) {
3343 view->rootObject()->setProperty("pixelSize", size);
3345 QVERIFY(qtext->height() <= qtextWithTag->height());
3347 QVERIFY(qtext->height() >= qtextWithTag->height());
3353 typedef qreal (*ExpectedBaseline)(QQuickText *item);
3354 Q_DECLARE_METATYPE(ExpectedBaseline)
3356 static qreal expectedBaselineTop(QQuickText *item)
3358 QFontMetricsF fm(item->font());
3362 static qreal expectedBaselineBottom(QQuickText *item)
3364 QFontMetricsF fm(item->font());
3365 return item->height() - item->contentHeight() + fm.ascent();
3368 static qreal expectedBaselineCenter(QQuickText *item)
3370 QFontMetricsF fm(item->font());
3371 return ((item->height() - item->contentHeight()) / 2) + fm.ascent();
3374 static qreal expectedBaselineBold(QQuickText *item)
3376 QFont font = item->font();
3378 QFontMetricsF fm(font);
3382 static qreal expectedBaselineImage(QQuickText *item)
3384 QFontMetricsF fm(item->font());
3385 // The line is positioned so the bottom of the line is aligned with the bottom of the image,
3386 // or image height - line height and the baseline is line position + ascent. Because
3387 // QTextLine's height is rounded up this can give slightly different results to image height
3389 return 181 - qCeil(fm.height()) + fm.ascent();
3392 static qreal expectedBaselineCustom(QQuickText *item)
3394 QFontMetricsF fm(item->font());
3395 return 16 + fm.ascent();
3398 static qreal expectedBaselineScaled(QQuickText *item)
3400 QFont font = item->font();
3401 QTextLayout layout(item->text().replace(QLatin1Char('\n'), QChar::LineSeparator));
3403 layout.setFont(font);
3405 layout.beginLayout();
3406 for (QTextLine line = layout.createLine(); line.isValid(); line = layout.createLine()) {
3407 line.setLineWidth(FLT_MAX);
3408 width = qMax(line.naturalTextWidth(), width);
3412 if (width < item->width()) {
3413 QFontMetricsF fm(layout.font());
3416 font.setPointSize(font.pointSize() - 1);
3417 } while (font.pointSize() > 0);
3421 static qreal expectedBaselineFixedBottom(QQuickText *item)
3423 QFontMetricsF fm(item->font());
3424 qreal dy = item->text().contains(QLatin1Char('\n'))
3427 return dy + fm.ascent();
3430 static qreal expectedBaselineProportionalBottom(QQuickText *item)
3432 QFontMetricsF fm(item->font());
3433 qreal dy = item->text().contains(QLatin1Char('\n'))
3434 ? 200 - (qCeil(fm.height()) * 3)
3435 : 200 - (qCeil(fm.height()) * 1.5);
3436 return dy + fm.ascent();
3439 void tst_qquicktext::baselineOffset_data()
3441 qRegisterMetaType<ExpectedBaseline>();
3442 QTest::addColumn<QString>("text");
3443 QTest::addColumn<QString>("wrappedText");
3444 QTest::addColumn<QByteArray>("bindings");
3445 QTest::addColumn<ExpectedBaseline>("expectedBaseline");
3446 QTest::addColumn<ExpectedBaseline>("expectedBaselineEmpty");
3448 QTest::newRow("top align")
3451 << QByteArray("height: 200; verticalAlignment: Text.AlignTop")
3452 << &expectedBaselineTop
3453 << &expectedBaselineTop;
3454 QTest::newRow("bottom align")
3457 << QByteArray("height: 200; verticalAlignment: Text.AlignBottom")
3458 << &expectedBaselineBottom
3459 << &expectedBaselineBottom;
3460 QTest::newRow("center align")
3463 << QByteArray("height: 200; verticalAlignment: Text.AlignVCenter")
3464 << &expectedBaselineCenter
3465 << &expectedBaselineCenter;
3467 QTest::newRow("bold")
3468 << "<b>hello world</b>"
3469 << "<b>hello<br/>world</b>"
3470 << QByteArray("height: 200")
3471 << &expectedBaselineTop
3472 << &expectedBaselineBold;
3474 QTest::newRow("richText")
3475 << "<b>hello world</b>"
3476 << "<b>hello<br/>world</b>"
3477 << QByteArray("height: 200; textFormat: Text.RichText")
3478 << &expectedBaselineTop
3479 << &expectedBaselineTop;
3481 QTest::newRow("elided")
3484 << QByteArray("width: 20; height: 8; elide: Text.ElideRight")
3485 << &expectedBaselineTop
3486 << &expectedBaselineTop;
3488 QTest::newRow("elided bottom align")
3490 << "hello\nworld!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
3491 << QByteArray("width: 200; height: 200; elide: Text.ElideRight; verticalAlignment: Text.AlignBottom")
3492 << &expectedBaselineBottom
3493 << &expectedBaselineBottom;
3495 QTest::newRow("image")
3496 << "hello <img src=\"images/heart200.png\" /> world"
3497 << "hello <img src=\"images/heart200.png\" /><br/>world"
3498 << QByteArray("height: 200\n; baseUrl: \"") + testFileUrl("reference").toEncoded() + QByteArray("\"")
3499 << &expectedBaselineImage
3500 << &expectedBaselineTop;
3502 QTest::newRow("customLine")
3505 << QByteArray("height: 200; onLineLaidOut: line.y += 16")
3506 << &expectedBaselineCustom
3507 << &expectedBaselineCustom;
3509 QTest::newRow("scaled font")
3512 << QByteArray("width: 200; minimumPointSize: 1; font.pointSize: 64; fontSizeMode: Text.HorizontalFit")
3513 << &expectedBaselineScaled
3514 << &expectedBaselineTop;
3516 QTest::newRow("fixed line height top align")
3519 << QByteArray("height: 200; lineHeightMode: Text.FixedHeight; lineHeight: 20; verticalAlignment: Text.AlignTop")
3520 << &expectedBaselineTop
3521 << &expectedBaselineTop;
3523 QTest::newRow("fixed line height bottom align")
3526 << QByteArray("height: 200; lineHeightMode: Text.FixedHeight; lineHeight: 20; verticalAlignment: Text.AlignBottom")
3527 << &expectedBaselineFixedBottom
3528 << &expectedBaselineFixedBottom;
3530 QTest::newRow("proportional line height top align")
3533 << QByteArray("height: 200; lineHeightMode: Text.ProportionalHeight; lineHeight: 1.5; verticalAlignment: Text.AlignTop")
3534 << &expectedBaselineTop
3535 << &expectedBaselineTop;
3537 QTest::newRow("proportional line height bottom align")
3540 << QByteArray("height: 200; lineHeightMode: Text.ProportionalHeight; lineHeight: 1.5; verticalAlignment: Text.AlignBottom")
3541 << &expectedBaselineProportionalBottom
3542 << &expectedBaselineProportionalBottom;
3545 void tst_qquicktext::baselineOffset()
3547 QFETCH(QString, text);
3548 QFETCH(QString, wrappedText);
3549 QFETCH(QByteArray, bindings);
3550 QFETCH(ExpectedBaseline, expectedBaseline);
3551 QFETCH(ExpectedBaseline, expectedBaselineEmpty);
3553 QQmlComponent component(&engine);
3555 "import QtQuick 2.0\n"
3560 QScopedPointer<QObject> object(component.create());
3562 QQuickText *item = qobject_cast<QQuickText *>(object.data());
3566 qreal baseline = expectedBaselineEmpty(item);
3568 QCOMPARE(item->baselineOffset(), baseline);
3570 item->setText(text);
3571 if (expectedBaseline != expectedBaselineEmpty)
3572 baseline = expectedBaseline(item);
3574 QCOMPARE(item->baselineOffset(), baseline);
3576 item->setText(wrappedText);
3577 QCOMPARE(item->baselineOffset(), expectedBaseline(item));
3580 QFont font = item->font();
3581 font.setPointSize(font.pointSize() + 8);
3584 QCOMPARE(item->baselineOffset(), expectedBaseline(item));
3586 item->setText(text);
3587 qreal baseline = expectedBaseline(item);
3588 QCOMPARE(item->baselineOffset(), baseline);
3590 item->setText(QString());
3591 if (expectedBaselineEmpty != expectedBaseline)
3592 baseline = expectedBaselineEmpty(item);
3594 QCOMPARE(item->baselineOffset(), baseline);
3598 void tst_qquicktext::htmlLists()
3600 QFETCH(QString, text);
3601 QFETCH(int, nbLines);
3603 QQuickView *view = createView(testFile("htmlLists.qml"));
3604 QQuickText *textObject = view->rootObject()->findChild<QQuickText*>("myText");
3606 QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject);
3607 QVERIFY(textPrivate != 0);
3608 QVERIFY(textPrivate->extra.isAllocated());
3610 QVERIFY(textObject != 0);
3611 textObject->setText(text);
3614 view->requestActivate();
3615 QVERIFY(QTest::qWaitForWindowActive(view));
3617 QCOMPARE(textPrivate->extra->doc->lineCount(), nbLines);
3622 void tst_qquicktext::htmlLists_data()
3624 QTest::addColumn<QString>("text");
3625 QTest::addColumn<int>("nbLines");
3627 QTest::newRow("ordered list") << "<ol><li>one<li>two<li>three" << 3;
3628 QTest::newRow("ordered list closed") << "<ol><li>one</li></ol>" << 1;
3629 QTest::newRow("ordered list alpha") << "<ol type=\"a\"><li>one</li><li>two</li></ol>" << 2;
3630 QTest::newRow("ordered list upper alpha") << "<ol type=\"A\"><li>one</li><li>two</li></ol>" << 2;
3631 QTest::newRow("ordered list roman") << "<ol type=\"i\"><li>one</li><li>two</li></ol>" << 2;
3632 QTest::newRow("ordered list upper roman") << "<ol type=\"I\"><li>one</li><li>two</li></ol>" << 2;
3633 QTest::newRow("ordered list bad") << "<ol type=\"z\"><li>one</li><li>two</li></ol>" << 2;
3634 QTest::newRow("unordered list") << "<ul><li>one<li>two" << 2;
3635 QTest::newRow("unordered list closed") << "<ul><li>one</li><li>two</li></ul>" << 2;
3636 QTest::newRow("unordered list disc") << "<ul type=\"disc\"><li>one</li><li>two</li></ul>" << 2;
3637 QTest::newRow("unordered list square") << "<ul type=\"square\"><li>one</li><li>two</li></ul>" << 2;
3638 QTest::newRow("unordered list bad") << "<ul type=\"bad\"><li>one</li><li>two</li></ul>" << 2;
3641 QTEST_MAIN(tst_qquicktext)
3643 #include "tst_qquicktext.moc"