Merge remote branch 'gerrit/api_changes' into merge-master
[profile/ivi/qtdeclarative.git] / tests / auto / quick / qquicktext / tst_qquicktext.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the test suite of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 #include <qtest.h>
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/qqmlvaluetype_p.h>
49 #include <QFontMetrics>
50 #include <QGraphicsSceneMouseEvent>
51 #include <qmath.h>
52 #include <QtQuick/QQuickView>
53 #include <private/qapplication_p.h>
54 #include <limits.h>
55 #include <QtGui/QMouseEvent>
56 #include "../../shared/util.h"
57 #include "testhttpserver.h"
58
59 DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
60
61 Q_DECLARE_METATYPE(QQuickText::TextFormat)
62
63 class tst_qquicktext : public QQmlDataTest
64 {
65     Q_OBJECT
66 public:
67     tst_qquicktext();
68
69 private slots:
70     void text();
71     void width();
72     void wrap();
73     void elide();
74     void multilineElide_data();
75     void multilineElide();
76     void textFormat();
77
78     void alignments_data();
79     void alignments();
80
81     void baseUrl();
82     void embeddedImages_data();
83     void embeddedImages();
84
85     void lineCount();
86     void lineHeight();
87
88     // ### these tests may be trivial
89     void horizontalAlignment();
90     void horizontalAlignment_RightToLeft();
91     void verticalAlignment();
92     void font();
93     void style();
94     void color();
95     void smooth();
96
97     // QQmlFontValueType
98     void weight();
99     void underline();
100     void overline();
101     void strikeout();
102     void capitalization();
103     void letterSpacing();
104     void wordSpacing();
105
106     void clickLink();
107
108     void implicitSize_data();
109     void implicitSize();
110     void contentSize();
111
112     void lineLaidOut();
113
114     void imgTagsBaseUrl_data();
115     void imgTagsBaseUrl();
116     void imgTagsAlign_data();
117     void imgTagsAlign();
118     void imgTagsMultipleImages();
119     void imgTagsElide();
120     void imgTagsUpdates();
121     void imgTagsError();
122     void fontSizeMode_data();
123     void fontSizeMode();
124     void fontSizeModeMultiline_data();
125     void fontSizeModeMultiline();
126     void multilengthStrings_data();
127     void multilengthStrings();
128     void fontFormatSizes_data();
129     void fontFormatSizes();
130
131 private:
132     QStringList standard;
133     QStringList richText;
134
135     QStringList horizontalAlignmentmentStrings;
136     QStringList verticalAlignmentmentStrings;
137
138     QList<Qt::Alignment> verticalAlignmentments;
139     QList<Qt::Alignment> horizontalAlignmentments;
140
141     QStringList styleStrings;
142     QList<QQuickText::TextStyle> styles;
143
144     QStringList colorStrings;
145
146     QQmlEngine engine;
147
148     QQuickView *createView(const QString &filename);
149 };
150
151 tst_qquicktext::tst_qquicktext()
152 {
153     standard << "the quick brown fox jumped over the lazy dog"
154             << "the quick brown fox\n jumped over the lazy dog";
155
156     richText << "<i>the <b>quick</b> brown <a href=\\\"http://www.google.com\\\">fox</a> jumped over the <b>lazy</b> dog</i>"
157             << "<i>the <b>quick</b> brown <a href=\\\"http://www.google.com\\\">fox</a><br>jumped over the <b>lazy</b> dog</i>";
158
159     horizontalAlignmentmentStrings << "AlignLeft"
160             << "AlignRight"
161             << "AlignHCenter";
162
163     verticalAlignmentmentStrings << "AlignTop"
164             << "AlignBottom"
165             << "AlignVCenter";
166
167     horizontalAlignmentments << Qt::AlignLeft
168             << Qt::AlignRight
169             << Qt::AlignHCenter;
170
171     verticalAlignmentments << Qt::AlignTop
172             << Qt::AlignBottom
173             << Qt::AlignVCenter;
174
175     styleStrings << "Normal"
176             << "Outline"
177             << "Raised"
178             << "Sunken";
179
180     styles << QQuickText::Normal
181             << QQuickText::Outline
182             << QQuickText::Raised
183             << QQuickText::Sunken;
184
185     colorStrings << "aliceblue"
186             << "antiquewhite"
187             << "aqua"
188             << "darkkhaki"
189             << "darkolivegreen"
190             << "dimgray"
191             << "palevioletred"
192             << "lightsteelblue"
193             << "#000000"
194             << "#AAAAAA"
195             << "#FFFFFF"
196             << "#2AC05F";
197     //
198     // need a different test to do alpha channel test
199     // << "#AA0011DD"
200     // << "#00F16B11";
201     //
202 }
203
204 QQuickView *tst_qquicktext::createView(const QString &filename)
205 {
206     QQuickView *canvas = new QQuickView(0);
207
208     canvas->setSource(QUrl::fromLocalFile(filename));
209     return canvas;
210 }
211
212 void tst_qquicktext::text()
213 {
214     {
215         QQmlComponent textComponent(&engine);
216         textComponent.setData("import QtQuick 2.0\nText { text: \"\" }", QUrl::fromLocalFile(""));
217         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
218
219         QVERIFY(textObject != 0);
220         QCOMPARE(textObject->text(), QString(""));
221         QVERIFY(textObject->width() == 0);
222
223         delete textObject;
224     }
225
226     for (int i = 0; i < standard.size(); i++)
227     {
228         QString componentStr = "import QtQuick 2.0\nText { text: \"" + standard.at(i) + "\" }";
229         QQmlComponent textComponent(&engine);
230         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
231
232         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
233
234         QVERIFY(textObject != 0);
235         QCOMPARE(textObject->text(), standard.at(i));
236         QVERIFY(textObject->width() > 0);
237
238         delete textObject;
239     }
240
241     for (int i = 0; i < richText.size(); i++)
242     {
243         QString componentStr = "import QtQuick 2.0\nText { text: \"" + richText.at(i) + "\" }";
244         QQmlComponent textComponent(&engine);
245         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
246         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
247
248         QVERIFY(textObject != 0);
249         QString expected = richText.at(i);
250         QCOMPARE(textObject->text(), expected.replace("\\\"", "\""));
251         QVERIFY(textObject->width() > 0);
252
253         delete textObject;
254     }
255 }
256
257 void tst_qquicktext::width()
258 {
259     // uses Font metrics to find the width for standard and document to find the width for rich
260     {
261         QQmlComponent textComponent(&engine);
262         textComponent.setData("import QtQuick 2.0\nText { text: \"\" }", QUrl::fromLocalFile(""));
263         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
264
265         QVERIFY(textObject != 0);
266         QCOMPARE(textObject->width(), 0.);
267
268         delete textObject;
269     }
270
271     bool requiresUnhintedMetrics = !qmlDisableDistanceField();
272
273     for (int i = 0; i < standard.size(); i++)
274     {
275         QVERIFY(!Qt::mightBeRichText(standard.at(i))); // self-test
276
277         QFont f;
278         qreal metricWidth = 0.0;
279
280         if (requiresUnhintedMetrics) {
281             QString s = standard.at(i);
282             s.replace(QLatin1Char('\n'), QChar::LineSeparator);
283
284             QTextLayout layout(s);
285             layout.setFlags(Qt::TextExpandTabs | Qt::TextShowMnemonic);
286             {
287                 QTextOption option;
288                 option.setUseDesignMetrics(true);
289                 layout.setTextOption(option);
290             }
291
292             layout.beginLayout();
293             forever {
294                 QTextLine line = layout.createLine();
295                 if (!line.isValid())
296                     break;
297             }
298
299             layout.endLayout();
300
301             metricWidth = layout.boundingRect().width();
302         } else {
303             QFontMetricsF fm(f);
304             metricWidth = fm.size(Qt::TextExpandTabs && Qt::TextShowMnemonic, standard.at(i)).width();
305         }
306
307         QString componentStr = "import QtQuick 2.0\nText { text: \"" + standard.at(i) + "\" }";
308         QQmlComponent textComponent(&engine);
309         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
310         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
311
312         QVERIFY(textObject != 0);
313         QVERIFY(textObject->boundingRect().width() > 0);
314         QCOMPARE(textObject->width(), qreal(metricWidth));
315         QVERIFY(textObject->textFormat() == QQuickText::AutoText); // setting text doesn't change format
316
317         delete textObject;
318     }
319
320     for (int i = 0; i < richText.size(); i++)
321     {
322         QVERIFY(Qt::mightBeRichText(richText.at(i))); // self-test
323
324         QString componentStr = "import QtQuick 2.0\nText { text: \"" + richText.at(i) + "\"; textFormat: Text.RichText }";
325         QQmlComponent textComponent(&engine);
326         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
327         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
328         QVERIFY(textObject != 0);
329
330         QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject);
331         QVERIFY(textPrivate != 0);
332         QVERIFY(textPrivate->extra.isAllocated());
333
334         QTextDocument *doc = textPrivate->extra->doc;
335         QVERIFY(doc != 0);
336
337         QCOMPARE(int(textObject->width()), int(doc->idealWidth()));
338         QVERIFY(textObject->textFormat() == QQuickText::RichText);
339
340         delete textObject;
341     }
342 }
343
344 void tst_qquicktext::wrap()
345 {
346     int textHeight = 0;
347     // for specified width and wrap set true
348     {
349         QQmlComponent textComponent(&engine);
350         textComponent.setData("import QtQuick 2.0\nText { text: \"Hello\"; wrapMode: Text.WordWrap; width: 300 }", QUrl::fromLocalFile(""));
351         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
352         textHeight = textObject->height();
353
354         QVERIFY(textObject != 0);
355         QVERIFY(textObject->wrapMode() == QQuickText::WordWrap);
356         QCOMPARE(textObject->width(), 300.);
357
358         delete textObject;
359     }
360
361     for (int i = 0; i < standard.size(); i++)
362     {
363         QString componentStr = "import QtQuick 2.0\nText { wrapMode: Text.WordWrap; width: 30; text: \"" + standard.at(i) + "\" }";
364         QQmlComponent textComponent(&engine);
365         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
366         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
367
368         QVERIFY(textObject != 0);
369         QCOMPARE(textObject->width(), 30.);
370         QVERIFY(textObject->height() > textHeight);
371
372         int oldHeight = textObject->height();
373         textObject->setWidth(100);
374         QVERIFY(textObject->height() < oldHeight);
375
376         delete textObject;
377     }
378
379     for (int i = 0; i < richText.size(); i++)
380     {
381         QString componentStr = "import QtQuick 2.0\nText { wrapMode: Text.WordWrap; width: 30; text: \"" + richText.at(i) + "\" }";
382         QQmlComponent textComponent(&engine);
383         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
384         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
385
386         QVERIFY(textObject != 0);
387         QCOMPARE(textObject->width(), 30.);
388         QVERIFY(textObject->height() > textHeight);
389
390         qreal oldHeight = textObject->height();
391         textObject->setWidth(100);
392         QVERIFY(textObject->height() < oldHeight);
393
394         delete textObject;
395     }
396
397     // richtext again with a fixed height
398     for (int i = 0; i < richText.size(); i++)
399     {
400         QString componentStr = "import QtQuick 2.0\nText { wrapMode: Text.WordWrap; width: 30; height: 50; text: \"" + richText.at(i) + "\" }";
401         QQmlComponent textComponent(&engine);
402         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
403         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
404
405         QVERIFY(textObject != 0);
406         QCOMPARE(textObject->width(), 30.);
407         QVERIFY(textObject->implicitHeight() > textHeight);
408
409         qreal oldHeight = textObject->implicitHeight();
410         textObject->setWidth(100);
411         QVERIFY(textObject->implicitHeight() < oldHeight);
412
413         delete textObject;
414     }
415 }
416
417 void tst_qquicktext::elide()
418 {
419     for (QQuickText::TextElideMode m = QQuickText::ElideLeft; m<=QQuickText::ElideNone; m=QQuickText::TextElideMode(int(m)+1)) {
420         const char* elidename[]={"ElideLeft", "ElideRight", "ElideMiddle", "ElideNone"};
421         QString elide = "elide: Text." + QString(elidename[int(m)]) + ";";
422
423         // XXX Poor coverage.
424
425         {
426             QQmlComponent textComponent(&engine);
427             textComponent.setData(("import QtQuick 2.0\nText { text: \"\"; "+elide+" width: 100 }").toLatin1(), QUrl::fromLocalFile(""));
428             QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
429
430             QCOMPARE(textObject->elideMode(), m);
431             QCOMPARE(textObject->width(), 100.);
432
433             delete textObject;
434         }
435
436         for (int i = 0; i < standard.size(); i++)
437         {
438             QString componentStr = "import QtQuick 2.0\nText { "+elide+" width: 100; text: \"" + standard.at(i) + "\" }";
439             QQmlComponent textComponent(&engine);
440             textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
441             QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
442
443             QCOMPARE(textObject->elideMode(), m);
444             QCOMPARE(textObject->width(), 100.);
445
446             if (m != QQuickText::ElideNone && !standard.at(i).contains('\n'))
447                 QVERIFY(textObject->contentWidth() <= textObject->width());
448
449             delete textObject;
450         }
451
452         for (int i = 0; i < richText.size(); i++)
453         {
454             QString componentStr = "import QtQuick 2.0\nText { "+elide+" width: 100; text: \"" + richText.at(i) + "\" }";
455             QQmlComponent textComponent(&engine);
456             textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
457             QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
458
459             QCOMPARE(textObject->elideMode(), m);
460             QCOMPARE(textObject->width(), 100.);
461
462             if (m != QQuickText::ElideNone && standard.at(i).contains("<br>"))
463                 QVERIFY(textObject->contentWidth() <= textObject->width());
464
465             delete textObject;
466         }
467     }
468 }
469
470 void tst_qquicktext::multilineElide_data()
471 {
472     QTest::addColumn<QQuickText::TextFormat>("format");
473     QTest::newRow("plain") << QQuickText::PlainText;
474     QTest::newRow("styled") << QQuickText::StyledText;
475 }
476
477 void tst_qquicktext::multilineElide()
478 {
479     QFETCH(QQuickText::TextFormat, format);
480     QQuickView *canvas = createView(testFile("multilineelide.qml"));
481
482     QQuickText *myText = qobject_cast<QQuickText*>(canvas->rootObject());
483     QVERIFY(myText != 0);
484     myText->setTextFormat(format);
485
486     QCOMPARE(myText->lineCount(), 3);
487     QCOMPARE(myText->truncated(), true);
488
489     qreal lineHeight = myText->contentHeight() / 3.;
490
491     // Set a valid height greater than the truncated content height and ensure the line count is
492     // unchanged.
493     myText->setHeight(200);
494     QCOMPARE(myText->lineCount(), 3);
495     QCOMPARE(myText->truncated(), true);
496
497     // reduce size and ensure fewer lines are drawn
498     myText->setHeight(lineHeight * 2);
499     QCOMPARE(myText->lineCount(), 2);
500
501     myText->setHeight(lineHeight);
502     QCOMPARE(myText->lineCount(), 1);
503
504     myText->setHeight(5);
505     QCOMPARE(myText->lineCount(), 1);
506
507     myText->setHeight(lineHeight * 3);
508     QCOMPARE(myText->lineCount(), 3);
509
510     // remove max count and show all lines.
511     myText->setHeight(1000);
512     myText->resetMaximumLineCount();
513
514     QCOMPARE(myText->truncated(), false);
515
516     // reduce size again
517     myText->setHeight(lineHeight * 2);
518     QCOMPARE(myText->lineCount(), 2);
519     QCOMPARE(myText->truncated(), true);
520
521     // change line height
522     myText->setLineHeight(1.1);
523     QCOMPARE(myText->lineCount(), 1);
524
525     delete canvas;
526 }
527
528 void tst_qquicktext::textFormat()
529 {
530     {
531         QQmlComponent textComponent(&engine);
532         textComponent.setData("import QtQuick 2.0\nText { text: \"Hello\"; textFormat: Text.RichText }", QUrl::fromLocalFile(""));
533         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
534
535         QVERIFY(textObject != 0);
536         QVERIFY(textObject->textFormat() == QQuickText::RichText);
537
538         QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject);
539         QVERIFY(textPrivate != 0);
540         QVERIFY(textPrivate->richText == true);
541
542         delete textObject;
543     }
544     {
545         QQmlComponent textComponent(&engine);
546         textComponent.setData("import QtQuick 2.0\nText { text: \"<b>Hello</b>\" }", QUrl::fromLocalFile(""));
547         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
548
549         QVERIFY(textObject != 0);
550         QVERIFY(textObject->textFormat() == QQuickText::AutoText);
551
552         QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject);
553         QVERIFY(textPrivate != 0);
554         QVERIFY(textPrivate->styledText == true);
555
556         delete textObject;
557     }
558     {
559         QQmlComponent textComponent(&engine);
560         textComponent.setData("import QtQuick 2.0\nText { text: \"<b>Hello</b>\"; textFormat: Text.PlainText }", QUrl::fromLocalFile(""));
561         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
562
563         QVERIFY(textObject != 0);
564         QVERIFY(textObject->textFormat() == QQuickText::PlainText);
565
566         delete textObject;
567     }
568 }
569
570
571 void tst_qquicktext::alignments_data()
572 {
573     QTest::addColumn<int>("hAlign");
574     QTest::addColumn<int>("vAlign");
575     QTest::addColumn<QString>("expectfile");
576
577     QTest::newRow("LT") << int(Qt::AlignLeft) << int(Qt::AlignTop) << testFile("alignments_lt.png");
578     QTest::newRow("RT") << int(Qt::AlignRight) << int(Qt::AlignTop) << testFile("alignments_rt.png");
579     QTest::newRow("CT") << int(Qt::AlignHCenter) << int(Qt::AlignTop) << testFile("alignments_ct.png");
580
581     QTest::newRow("LB") << int(Qt::AlignLeft) << int(Qt::AlignBottom) << testFile("alignments_lb.png");
582     QTest::newRow("RB") << int(Qt::AlignRight) << int(Qt::AlignBottom) << testFile("alignments_rb.png");
583     QTest::newRow("CB") << int(Qt::AlignHCenter) << int(Qt::AlignBottom) << testFile("alignments_cb.png");
584
585     QTest::newRow("LC") << int(Qt::AlignLeft) << int(Qt::AlignVCenter) << testFile("alignments_lc.png");
586     QTest::newRow("RC") << int(Qt::AlignRight) << int(Qt::AlignVCenter) << testFile("alignments_rc.png");
587     QTest::newRow("CC") << int(Qt::AlignHCenter) << int(Qt::AlignVCenter) << testFile("alignments_cc.png");
588 }
589
590
591 void tst_qquicktext::alignments()
592 {
593     QSKIP("Text alignment pixmap comparison tests will not work with scenegraph");
594 #if (0)// No widgets in scenegraph
595     QFETCH(int, hAlign);
596     QFETCH(int, vAlign);
597     QFETCH(QString, expectfile);
598
599     QQuickView *canvas = createView(testFile("alignments.qml"));
600     canvas->show();
601     canvas->requestActivateWindow();
602     QTest::qWait(50);
603     QTRY_COMPARE(QGuiApplication::activeWindow(), static_cast<QWidget *>(canvas));
604
605     QObject *ob = canvas->rootObject();
606     QVERIFY(ob != 0);
607     ob->setProperty("horizontalAlignment",hAlign);
608     ob->setProperty("verticalAlignment",vAlign);
609     QTRY_COMPARE(ob->property("running").toBool(),false);
610     QImage actual(canvas->width(), canvas->height(), QImage::Format_RGB32);
611     actual.fill(qRgb(255,255,255));
612     QPainter p(&actual);
613     canvas->render(&p);
614
615     QImage expect(expectfile);
616     if (QGuiApplicationPrivate::graphics_system_name == "raster" || QGuiApplicationPrivate::graphics_system_name == "") {
617         QCOMPARE(actual,expect);
618     }
619     delete canvas;
620 #endif
621 }
622
623 //the alignment tests may be trivial o.oa
624 void tst_qquicktext::horizontalAlignment()
625 {
626     //test one align each, and then test if two align fails.
627
628     for (int i = 0; i < standard.size(); i++)
629     {
630         for (int j=0; j < horizontalAlignmentmentStrings.size(); j++)
631         {
632             QString componentStr = "import QtQuick 2.0\nText { horizontalAlignment: \"" + horizontalAlignmentmentStrings.at(j) + "\"; text: \"" + standard.at(i) + "\" }";
633             QQmlComponent textComponent(&engine);
634             textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
635             QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
636
637             QCOMPARE((int)textObject->hAlign(), (int)horizontalAlignmentments.at(j));
638
639             delete textObject;
640         }
641     }
642
643     for (int i = 0; i < richText.size(); i++)
644     {
645         for (int j=0; j < horizontalAlignmentmentStrings.size(); j++)
646         {
647             QString componentStr = "import QtQuick 2.0\nText { horizontalAlignment: \"" + horizontalAlignmentmentStrings.at(j) + "\"; text: \"" + richText.at(i) + "\" }";
648             QQmlComponent textComponent(&engine);
649             textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
650             QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
651
652             QCOMPARE((int)textObject->hAlign(), (int)horizontalAlignmentments.at(j));
653
654             delete textObject;
655         }
656     }
657
658 }
659
660 void tst_qquicktext::horizontalAlignment_RightToLeft()
661 {
662     QQuickView *canvas = createView(testFile("horizontalAlignment_RightToLeft.qml"));
663     QQuickText *text = canvas->rootObject()->findChild<QQuickText*>("text");
664     QVERIFY(text != 0);
665     canvas->show();
666
667     QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(text);
668     QVERIFY(textPrivate != 0);
669
670     QTRY_VERIFY(textPrivate->layout.lineCount());
671
672     // implicit alignment should follow the reading direction of RTL text
673     QCOMPARE(text->hAlign(), QQuickText::AlignRight);
674     QCOMPARE(text->effectiveHAlign(), text->hAlign());
675     QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > canvas->width()/2);
676
677     // explicitly left aligned text
678     text->setHAlign(QQuickText::AlignLeft);
679     QCOMPARE(text->hAlign(), QQuickText::AlignLeft);
680     QCOMPARE(text->effectiveHAlign(), text->hAlign());
681     QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() < canvas->width()/2);
682
683     // explicitly right aligned text
684     text->setHAlign(QQuickText::AlignRight);
685     QCOMPARE(text->hAlign(), QQuickText::AlignRight);
686     QCOMPARE(text->effectiveHAlign(), text->hAlign());
687     QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > canvas->width()/2);
688
689     // change to rich text
690     QString textString = text->text();
691     text->setText(QString("<i>") + textString + QString("</i>"));
692     text->setTextFormat(QQuickText::RichText);
693     text->resetHAlign();
694
695     // implicitly aligned rich text should follow the reading direction of text
696     QCOMPARE(text->hAlign(), QQuickText::AlignRight);
697     QCOMPARE(text->effectiveHAlign(), text->hAlign());
698     QVERIFY(textPrivate->extra.isAllocated());
699     QVERIFY(textPrivate->extra->doc->defaultTextOption().alignment() & Qt::AlignLeft);
700
701     // explicitly left aligned rich text
702     text->setHAlign(QQuickText::AlignLeft);
703     QCOMPARE(text->hAlign(), QQuickText::AlignLeft);
704     QCOMPARE(text->effectiveHAlign(), text->hAlign());
705     QVERIFY(textPrivate->extra->doc->defaultTextOption().alignment() & Qt::AlignRight);
706
707     // explicitly right aligned rich text
708     text->setHAlign(QQuickText::AlignRight);
709     QCOMPARE(text->hAlign(), QQuickText::AlignRight);
710     QCOMPARE(text->effectiveHAlign(), text->hAlign());
711     QVERIFY(textPrivate->extra->doc->defaultTextOption().alignment() & Qt::AlignLeft);
712
713     text->setText(textString);
714     text->setTextFormat(QQuickText::PlainText);
715
716     // explicitly center aligned
717     text->setHAlign(QQuickText::AlignHCenter);
718     QCOMPARE(text->hAlign(), QQuickText::AlignHCenter);
719     QCOMPARE(text->effectiveHAlign(), text->hAlign());
720     QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() < canvas->width()/2);
721     QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().right() > canvas->width()/2);
722
723     // reseted alignment should go back to following the text reading direction
724     text->resetHAlign();
725     QCOMPARE(text->hAlign(), QQuickText::AlignRight);
726     QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > canvas->width()/2);
727
728     // mirror the text item
729     QQuickItemPrivate::get(text)->setLayoutMirror(true);
730
731     // mirrored implicit alignment should continue to follow the reading direction of the text
732     QCOMPARE(text->hAlign(), QQuickText::AlignRight);
733     QCOMPARE(text->effectiveHAlign(), QQuickText::AlignRight);
734     QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > canvas->width()/2);
735
736     // mirrored explicitly right aligned behaves as left aligned
737     text->setHAlign(QQuickText::AlignRight);
738     QCOMPARE(text->hAlign(), QQuickText::AlignRight);
739     QCOMPARE(text->effectiveHAlign(), QQuickText::AlignLeft);
740     QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() < canvas->width()/2);
741
742     // mirrored explicitly left aligned behaves as right aligned
743     text->setHAlign(QQuickText::AlignLeft);
744     QCOMPARE(text->hAlign(), QQuickText::AlignLeft);
745     QCOMPARE(text->effectiveHAlign(), QQuickText::AlignRight);
746     QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > canvas->width()/2);
747
748     // disable mirroring
749     QQuickItemPrivate::get(text)->setLayoutMirror(false);
750     text->resetHAlign();
751
752     // English text should be implicitly left aligned
753     text->setText("Hello world!");
754     QCOMPARE(text->hAlign(), QQuickText::AlignLeft);
755     QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() < canvas->width()/2);
756
757     // empty text with implicit alignment follows the system locale-based
758     // keyboard input direction from QInputMethod::inputDirection()
759     text->setText("");
760     QCOMPARE(text->hAlign(), qApp->inputMethod()->inputDirection() == Qt::LeftToRight ?
761                                   QQuickText::AlignLeft : QQuickText::AlignRight);
762     text->setHAlign(QQuickText::AlignRight);
763     QCOMPARE(text->hAlign(), QQuickText::AlignRight);
764
765     delete canvas;
766
767     // alignment of Text with no text set to it
768     QString componentStr = "import QtQuick 2.0\nText {}";
769     QQmlComponent textComponent(&engine);
770     textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
771     QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
772     QCOMPARE(textObject->hAlign(), qApp->inputMethod()->inputDirection() == Qt::LeftToRight ?
773                                   QQuickText::AlignLeft : QQuickText::AlignRight);
774     delete textObject;
775 }
776
777 void tst_qquicktext::verticalAlignment()
778 {
779     //test one align each, and then test if two align fails.
780
781     for (int i = 0; i < standard.size(); i++)
782     {
783         for (int j=0; j < verticalAlignmentmentStrings.size(); j++)
784         {
785             QString componentStr = "import QtQuick 2.0\nText { verticalAlignment: \"" + verticalAlignmentmentStrings.at(j) + "\"; text: \"" + standard.at(i) + "\" }";
786             QQmlComponent textComponent(&engine);
787             textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
788             QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
789
790             QVERIFY(textObject != 0);
791             QCOMPARE((int)textObject->vAlign(), (int)verticalAlignmentments.at(j));
792
793             delete textObject;
794         }
795     }
796
797     for (int i = 0; i < richText.size(); i++)
798     {
799         for (int j=0; j < verticalAlignmentmentStrings.size(); j++)
800         {
801             QString componentStr = "import QtQuick 2.0\nText { verticalAlignment: \"" + verticalAlignmentmentStrings.at(j) + "\"; text: \"" + richText.at(i) + "\" }";
802             QQmlComponent textComponent(&engine);
803             textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
804             QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
805
806             QVERIFY(textObject != 0);
807             QCOMPARE((int)textObject->vAlign(), (int)verticalAlignmentments.at(j));
808
809             delete textObject;
810         }
811     }
812
813 }
814
815 void tst_qquicktext::font()
816 {
817     //test size, then bold, then italic, then family
818     {
819         QString componentStr = "import QtQuick 2.0\nText { font.pointSize: 40; text: \"Hello World\" }";
820         QQmlComponent textComponent(&engine);
821         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
822         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
823
824         QCOMPARE(textObject->font().pointSize(), 40);
825         QCOMPARE(textObject->font().bold(), false);
826         QCOMPARE(textObject->font().italic(), false);
827
828         delete textObject;
829     }
830
831     {
832         QString componentStr = "import QtQuick 2.0\nText { font.pixelSize: 40; text: \"Hello World\" }";
833         QQmlComponent textComponent(&engine);
834         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
835         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
836
837         QCOMPARE(textObject->font().pixelSize(), 40);
838         QCOMPARE(textObject->font().bold(), false);
839         QCOMPARE(textObject->font().italic(), false);
840
841         delete textObject;
842     }
843
844     {
845         QString componentStr = "import QtQuick 2.0\nText { font.bold: true; text: \"Hello World\" }";
846         QQmlComponent textComponent(&engine);
847         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
848         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
849
850         QCOMPARE(textObject->font().bold(), true);
851         QCOMPARE(textObject->font().italic(), false);
852
853         delete textObject;
854     }
855
856     {
857         QString componentStr = "import QtQuick 2.0\nText { font.italic: true; text: \"Hello World\" }";
858         QQmlComponent textComponent(&engine);
859         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
860         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
861
862         QCOMPARE(textObject->font().italic(), true);
863         QCOMPARE(textObject->font().bold(), false);
864
865         delete textObject;
866     }
867
868     {
869         QString componentStr = "import QtQuick 2.0\nText { font.family: \"Helvetica\"; text: \"Hello World\" }";
870         QQmlComponent textComponent(&engine);
871         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
872         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
873
874         QCOMPARE(textObject->font().family(), QString("Helvetica"));
875         QCOMPARE(textObject->font().bold(), false);
876         QCOMPARE(textObject->font().italic(), false);
877
878         delete textObject;
879     }
880
881     {
882         QString componentStr = "import QtQuick 2.0\nText { font.family: \"\"; text: \"Hello World\" }";
883         QQmlComponent textComponent(&engine);
884         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
885         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
886
887         QCOMPARE(textObject->font().family(), QString(""));
888
889         delete textObject;
890     }
891 }
892
893 void tst_qquicktext::style()
894 {
895     //test style
896     for (int i = 0; i < styles.size(); i++)
897     {
898         QString componentStr = "import QtQuick 2.0\nText { style: \"" + styleStrings.at(i) + "\"; styleColor: \"white\"; text: \"Hello World\" }";
899         QQmlComponent textComponent(&engine);
900         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
901         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
902
903         QCOMPARE((int)textObject->style(), (int)styles.at(i));
904         QCOMPARE(textObject->styleColor(), QColor("white"));
905
906         delete textObject;
907     }
908     QString componentStr = "import QtQuick 2.0\nText { text: \"Hello World\" }";
909     QQmlComponent textComponent(&engine);
910     textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
911     QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
912
913     QRectF brPre = textObject->boundingRect();
914     textObject->setStyle(QQuickText::Outline);
915     QRectF brPost = textObject->boundingRect();
916
917     QVERIFY(brPre.width() < brPost.width());
918     QVERIFY(brPre.height() < brPost.height());
919
920     delete textObject;
921 }
922
923 void tst_qquicktext::color()
924 {
925     //test style
926     for (int i = 0; i < colorStrings.size(); i++)
927     {
928         QString componentStr = "import QtQuick 2.0\nText { color: \"" + colorStrings.at(i) + "\"; text: \"Hello World\" }";
929         QQmlComponent textComponent(&engine);
930         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
931         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
932
933         QCOMPARE(textObject->color(), QColor(colorStrings.at(i)));
934         QCOMPARE(textObject->styleColor(), QColor("black"));
935         QCOMPARE(textObject->linkColor(), QColor("blue"));
936
937         delete textObject;
938     }
939
940     for (int i = 0; i < colorStrings.size(); i++)
941     {
942         QString componentStr = "import QtQuick 2.0\nText { styleColor: \"" + colorStrings.at(i) + "\"; text: \"Hello World\" }";
943         QQmlComponent textComponent(&engine);
944         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
945         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
946
947         QCOMPARE(textObject->styleColor(), QColor(colorStrings.at(i)));
948         // default color to black?
949         QCOMPARE(textObject->color(), QColor("black"));
950         QCOMPARE(textObject->linkColor(), QColor("blue"));
951
952         delete textObject;
953     }
954
955     for (int i = 0; i < colorStrings.size(); i++)
956     {
957         QString componentStr = "import QtQuick 2.0\nText { linkColor: \"" + colorStrings.at(i) + "\"; text: \"Hello World\" }";
958         QQmlComponent textComponent(&engine);
959         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
960         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
961
962         QCOMPARE(textObject->styleColor(), QColor("black"));
963         QCOMPARE(textObject->color(), QColor("black"));
964         QCOMPARE(textObject->linkColor(), QColor(colorStrings.at(i)));
965
966         delete textObject;
967     }
968
969     for (int i = 0; i < colorStrings.size(); i++)
970     {
971         for (int j = 0; j < colorStrings.size(); j++)
972         {
973             QString componentStr = "import QtQuick 2.0\nText { "
974                     "color: \"" + colorStrings.at(i) + "\"; "
975                     "styleColor: \"" + colorStrings.at(j) + "\"; "
976                     "linkColor: \"" + colorStrings.at(j) + "\"; "
977                     "text: \"Hello World\" }";
978             QQmlComponent textComponent(&engine);
979             textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
980             QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
981
982             QCOMPARE(textObject->color(), QColor(colorStrings.at(i)));
983             QCOMPARE(textObject->styleColor(), QColor(colorStrings.at(j)));
984             QCOMPARE(textObject->linkColor(), QColor(colorStrings.at(j)));
985
986             delete textObject;
987         }
988     }
989     {
990         QString colorStr = "#AA001234";
991         QColor testColor("#001234");
992         testColor.setAlpha(170);
993
994         QString componentStr = "import QtQuick 2.0\nText { color: \"" + colorStr + "\"; text: \"Hello World\" }";
995         QQmlComponent textComponent(&engine);
996         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
997         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
998
999         QCOMPARE(textObject->color(), testColor);
1000
1001         delete textObject;
1002     } {
1003         QString colorStr = "#001234";
1004         QColor testColor(colorStr);
1005
1006         QString componentStr = "import QtQuick 2.0\nText { color: \"" + colorStr + "\"; text: \"Hello World\" }";
1007         QQmlComponent textComponent(&engine);
1008         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1009         QScopedPointer<QObject> object(textComponent.create());
1010         QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
1011
1012         QSignalSpy spy(textObject, SIGNAL(colorChanged()));
1013
1014         QCOMPARE(textObject->color(), testColor);
1015         textObject->setColor(testColor);
1016         QCOMPARE(textObject->color(), testColor);
1017         QCOMPARE(spy.count(), 0);
1018
1019         testColor = QColor("black");
1020         textObject->setColor(testColor);
1021         QCOMPARE(textObject->color(), testColor);
1022         QCOMPARE(spy.count(), 1);
1023     } {
1024         QString colorStr = "#001234";
1025         QColor testColor(colorStr);
1026
1027         QString componentStr = "import QtQuick 2.0\nText { styleColor: \"" + colorStr + "\"; text: \"Hello World\" }";
1028         QQmlComponent textComponent(&engine);
1029         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1030         QScopedPointer<QObject> object(textComponent.create());
1031         QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
1032
1033         QSignalSpy spy(textObject, SIGNAL(styleColorChanged()));
1034
1035         QCOMPARE(textObject->styleColor(), testColor);
1036         textObject->setStyleColor(testColor);
1037         QCOMPARE(textObject->styleColor(), testColor);
1038         QCOMPARE(spy.count(), 0);
1039
1040         testColor = QColor("black");
1041         textObject->setStyleColor(testColor);
1042         QCOMPARE(textObject->styleColor(), testColor);
1043         QCOMPARE(spy.count(), 1);
1044     } {
1045         QString colorStr = "#001234";
1046         QColor testColor(colorStr);
1047
1048         QString componentStr = "import QtQuick 2.0\nText { linkColor: \"" + colorStr + "\"; text: \"Hello World\" }";
1049         QQmlComponent textComponent(&engine);
1050         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1051         QScopedPointer<QObject> object(textComponent.create());
1052         QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
1053
1054         QSignalSpy spy(textObject, SIGNAL(linkColorChanged()));
1055
1056         QCOMPARE(textObject->linkColor(), testColor);
1057         textObject->setLinkColor(testColor);
1058         QCOMPARE(textObject->linkColor(), testColor);
1059         QCOMPARE(spy.count(), 0);
1060
1061         testColor = QColor("black");
1062         textObject->setLinkColor(testColor);
1063         QCOMPARE(textObject->linkColor(), testColor);
1064         QCOMPARE(spy.count(), 1);
1065     }
1066 }
1067
1068 void tst_qquicktext::smooth()
1069 {
1070     for (int i = 0; i < standard.size(); i++)
1071     {
1072         {
1073             QString componentStr = "import QtQuick 2.0\nText { smooth: true; text: \"" + standard.at(i) + "\" }";
1074             QQmlComponent textComponent(&engine);
1075             textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1076             QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1077             QCOMPARE(textObject->smooth(), true);
1078
1079             delete textObject;
1080         }
1081         {
1082             QString componentStr = "import QtQuick 2.0\nText { text: \"" + standard.at(i) + "\" }";
1083             QQmlComponent textComponent(&engine);
1084             textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1085             QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1086             QCOMPARE(textObject->smooth(), false);
1087
1088             delete textObject;
1089         }
1090     }
1091     for (int i = 0; i < richText.size(); i++)
1092     {
1093         {
1094             QString componentStr = "import QtQuick 2.0\nText { smooth: true; text: \"" + richText.at(i) + "\" }";
1095             QQmlComponent textComponent(&engine);
1096             textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1097             QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1098             QCOMPARE(textObject->smooth(), true);
1099
1100             delete textObject;
1101         }
1102         {
1103             QString componentStr = "import QtQuick 2.0\nText { text: \"" + richText.at(i) + "\" }";
1104             QQmlComponent textComponent(&engine);
1105             textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1106             QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1107             QCOMPARE(textObject->smooth(), false);
1108
1109             delete textObject;
1110         }
1111     }
1112 }
1113
1114 void tst_qquicktext::weight()
1115 {
1116     {
1117         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
1118         QQmlComponent textComponent(&engine);
1119         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1120         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1121
1122         QVERIFY(textObject != 0);
1123         QCOMPARE((int)textObject->font().weight(), (int)QQmlFontValueType::Normal);
1124
1125         delete textObject;
1126     }
1127     {
1128         QString componentStr = "import QtQuick 2.0\nText { font.weight: \"Bold\"; text: \"Hello world!\" }";
1129         QQmlComponent textComponent(&engine);
1130         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1131         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1132
1133         QVERIFY(textObject != 0);
1134         QCOMPARE((int)textObject->font().weight(), (int)QQmlFontValueType::Bold);
1135
1136         delete textObject;
1137     }
1138 }
1139
1140 void tst_qquicktext::underline()
1141 {
1142     {
1143         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
1144         QQmlComponent textComponent(&engine);
1145         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1146         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1147
1148         QVERIFY(textObject != 0);
1149         QCOMPARE(textObject->font().underline(), false);
1150
1151         delete textObject;
1152     }
1153     {
1154         QString componentStr = "import QtQuick 2.0\nText { font.underline: true; text: \"Hello world!\" }";
1155         QQmlComponent textComponent(&engine);
1156         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1157         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1158
1159         QVERIFY(textObject != 0);
1160         QCOMPARE(textObject->font().underline(), true);
1161
1162         delete textObject;
1163     }
1164 }
1165
1166 void tst_qquicktext::overline()
1167 {
1168     {
1169         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
1170         QQmlComponent textComponent(&engine);
1171         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1172         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1173
1174         QVERIFY(textObject != 0);
1175         QCOMPARE(textObject->font().overline(), false);
1176
1177         delete textObject;
1178     }
1179     {
1180         QString componentStr = "import QtQuick 2.0\nText { font.overline: true; text: \"Hello world!\" }";
1181         QQmlComponent textComponent(&engine);
1182         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1183         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1184
1185         QVERIFY(textObject != 0);
1186         QCOMPARE(textObject->font().overline(), true);
1187
1188         delete textObject;
1189     }
1190 }
1191
1192 void tst_qquicktext::strikeout()
1193 {
1194     {
1195         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
1196         QQmlComponent textComponent(&engine);
1197         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1198         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1199
1200         QVERIFY(textObject != 0);
1201         QCOMPARE(textObject->font().strikeOut(), false);
1202
1203         delete textObject;
1204     }
1205     {
1206         QString componentStr = "import QtQuick 2.0\nText { font.strikeout: true; text: \"Hello world!\" }";
1207         QQmlComponent textComponent(&engine);
1208         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1209         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1210
1211         QVERIFY(textObject != 0);
1212         QCOMPARE(textObject->font().strikeOut(), true);
1213
1214         delete textObject;
1215     }
1216 }
1217
1218 void tst_qquicktext::capitalization()
1219 {
1220     {
1221         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
1222         QQmlComponent textComponent(&engine);
1223         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1224         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1225
1226         QVERIFY(textObject != 0);
1227         QCOMPARE((int)textObject->font().capitalization(), (int)QQmlFontValueType::MixedCase);
1228
1229         delete textObject;
1230     }
1231     {
1232         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.capitalization: \"AllUppercase\" }";
1233         QQmlComponent textComponent(&engine);
1234         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1235         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1236
1237         QVERIFY(textObject != 0);
1238         QCOMPARE((int)textObject->font().capitalization(), (int)QQmlFontValueType::AllUppercase);
1239
1240         delete textObject;
1241     }
1242     {
1243         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.capitalization: \"AllLowercase\" }";
1244         QQmlComponent textComponent(&engine);
1245         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1246         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1247
1248         QVERIFY(textObject != 0);
1249         QCOMPARE((int)textObject->font().capitalization(), (int)QQmlFontValueType::AllLowercase);
1250
1251         delete textObject;
1252     }
1253     {
1254         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.capitalization: \"SmallCaps\" }";
1255         QQmlComponent textComponent(&engine);
1256         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1257         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1258
1259         QVERIFY(textObject != 0);
1260         QCOMPARE((int)textObject->font().capitalization(), (int)QQmlFontValueType::SmallCaps);
1261
1262         delete textObject;
1263     }
1264     {
1265         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.capitalization: \"Capitalize\" }";
1266         QQmlComponent textComponent(&engine);
1267         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1268         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1269
1270         QVERIFY(textObject != 0);
1271         QCOMPARE((int)textObject->font().capitalization(), (int)QQmlFontValueType::Capitalize);
1272
1273         delete textObject;
1274     }
1275 }
1276
1277 void tst_qquicktext::letterSpacing()
1278 {
1279     {
1280         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
1281         QQmlComponent textComponent(&engine);
1282         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1283         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1284
1285         QVERIFY(textObject != 0);
1286         QCOMPARE(textObject->font().letterSpacing(), 0.0);
1287
1288         delete textObject;
1289     }
1290     {
1291         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.letterSpacing: -2 }";
1292         QQmlComponent textComponent(&engine);
1293         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1294         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1295
1296         QVERIFY(textObject != 0);
1297         QCOMPARE(textObject->font().letterSpacing(), -2.);
1298
1299         delete textObject;
1300     }
1301     {
1302         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.letterSpacing: 3 }";
1303         QQmlComponent textComponent(&engine);
1304         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1305         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1306
1307         QVERIFY(textObject != 0);
1308         QCOMPARE(textObject->font().letterSpacing(), 3.);
1309
1310         delete textObject;
1311     }
1312 }
1313
1314 void tst_qquicktext::wordSpacing()
1315 {
1316     {
1317         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
1318         QQmlComponent textComponent(&engine);
1319         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1320         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1321
1322         QVERIFY(textObject != 0);
1323         QCOMPARE(textObject->font().wordSpacing(), 0.0);
1324
1325         delete textObject;
1326     }
1327     {
1328         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.wordSpacing: -50 }";
1329         QQmlComponent textComponent(&engine);
1330         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1331         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1332
1333         QVERIFY(textObject != 0);
1334         QCOMPARE(textObject->font().wordSpacing(), -50.);
1335
1336         delete textObject;
1337     }
1338     {
1339         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.wordSpacing: 200 }";
1340         QQmlComponent textComponent(&engine);
1341         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1342         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1343
1344         QVERIFY(textObject != 0);
1345         QCOMPARE(textObject->font().wordSpacing(), 200.);
1346
1347         delete textObject;
1348     }
1349 }
1350
1351
1352
1353
1354 class EventSender : public QQuickItem
1355 {
1356 public:
1357     void sendEvent(QMouseEvent *event) {
1358         if (event->type() == QEvent::MouseButtonPress)
1359             mousePressEvent(event);
1360         else if (event->type() == QEvent::MouseButtonRelease)
1361             mouseReleaseEvent(event);
1362         else
1363             qWarning() << "Trying to send unsupported event type";
1364     }
1365 };
1366
1367 class LinkTest : public QObject
1368 {
1369     Q_OBJECT
1370 public:
1371     LinkTest() {}
1372
1373     QString link;
1374
1375 public slots:
1376     void linkClicked(QString l) { link = l; }
1377 };
1378
1379 void tst_qquicktext::clickLink()
1380 {
1381     {
1382         QString componentStr = "import QtQuick 2.0\nText { text: \"<a href=\\\"http://qt.nokia.com\\\">Hello world!</a>\" }";
1383         QQmlComponent textComponent(&engine);
1384         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1385         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1386
1387         QVERIFY(textObject != 0);
1388
1389         LinkTest test;
1390         QObject::connect(textObject, SIGNAL(linkActivated(QString)), &test, SLOT(linkClicked(QString)));
1391
1392         {
1393             QMouseEvent me(QEvent::MouseButtonPress,QPointF(textObject->x()/2, textObject->y()/2), Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
1394             static_cast<EventSender*>(static_cast<QQuickItem*>(textObject))->sendEvent(&me);
1395
1396         }
1397
1398         {
1399             QMouseEvent me(QEvent::MouseButtonRelease,QPointF(textObject->x()/2, textObject->y()/2), Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
1400             static_cast<EventSender*>(static_cast<QQuickItem*>(textObject))->sendEvent(&me);
1401
1402         }
1403
1404
1405         QCOMPARE(test.link, QLatin1String("http://qt.nokia.com"));
1406
1407         delete textObject;
1408     }
1409 }
1410
1411 void tst_qquicktext::baseUrl()
1412 {
1413     QUrl localUrl("file:///tests/text.qml");
1414     QUrl remoteUrl("http://qt.nokia.com/test.qml");
1415
1416     QQmlComponent textComponent(&engine);
1417     textComponent.setData("import QtQuick 2.0\n Text {}", localUrl);
1418     QQuickText *textObject = qobject_cast<QQuickText *>(textComponent.create());
1419
1420     QCOMPARE(textObject->baseUrl(), localUrl);
1421
1422     QSignalSpy spy(textObject, SIGNAL(baseUrlChanged()));
1423
1424     textObject->setBaseUrl(localUrl);
1425     QCOMPARE(textObject->baseUrl(), localUrl);
1426     QCOMPARE(spy.count(), 0);
1427
1428     textObject->setBaseUrl(remoteUrl);
1429     QCOMPARE(textObject->baseUrl(), remoteUrl);
1430     QCOMPARE(spy.count(), 1);
1431
1432     textObject->resetBaseUrl();
1433     QCOMPARE(textObject->baseUrl(), localUrl);
1434     QCOMPARE(spy.count(), 2);
1435 }
1436
1437 void tst_qquicktext::embeddedImages_data()
1438 {
1439     QTest::addColumn<QUrl>("qmlfile");
1440     QTest::addColumn<QString>("error");
1441     QTest::newRow("local") << testFileUrl("embeddedImagesLocal.qml") << "";
1442     QTest::newRow("local-error") << testFileUrl("embeddedImagesLocalError.qml")
1443         << testFileUrl("embeddedImagesLocalError.qml").toString()+":3:1: QML Text: Cannot open: " + testFileUrl("http/notexists.png").toString();
1444     QTest::newRow("local") << testFileUrl("embeddedImagesLocalRelative.qml") << "";
1445     QTest::newRow("remote") << testFileUrl("embeddedImagesRemote.qml") << "";
1446     QTest::newRow("remote-error") << testFileUrl("embeddedImagesRemoteError.qml")
1447         << testFileUrl("embeddedImagesRemoteError.qml").toString()+":3:1: QML Text: Error downloading http://127.0.0.1:14453/notexists.png - server replied: Not found";
1448     QTest::newRow("remote") << testFileUrl("embeddedImagesRemoteRelative.qml") << "";
1449 }
1450
1451 void tst_qquicktext::embeddedImages()
1452 {
1453     // Tests QTBUG-9900
1454
1455     QFETCH(QUrl, qmlfile);
1456     QFETCH(QString, error);
1457
1458     TestHTTPServer server(14453);
1459     server.serveDirectory(testFile("http"));
1460
1461     if (!error.isEmpty())
1462         QTest::ignoreMessage(QtWarningMsg, error.toLatin1());
1463
1464     QQmlComponent textComponent(&engine, qmlfile);
1465     QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1466
1467     QVERIFY(textObject != 0);
1468
1469     QTRY_COMPARE(textObject->resourcesLoading(), 0);
1470
1471     QPixmap pm(testFile("http/exists.png"));
1472     if (error.isEmpty()) {
1473         QCOMPARE(textObject->width(), double(pm.width()));
1474         QCOMPARE(textObject->height(), double(pm.height()));
1475     } else {
1476         QVERIFY(16 != pm.width()); // check test is effective
1477         QCOMPARE(textObject->width(), 16.0); // default size of QTextDocument broken image icon
1478         QCOMPARE(textObject->height(), 16.0);
1479     }
1480
1481     delete textObject;
1482 }
1483
1484 void tst_qquicktext::lineCount()
1485 {
1486     QQuickView *canvas = createView(testFile("lineCount.qml"));
1487
1488     QQuickText *myText = canvas->rootObject()->findChild<QQuickText*>("myText");
1489     QVERIFY(myText != 0);
1490
1491     QVERIFY(myText->lineCount() > 1);
1492     QVERIFY(!myText->truncated());
1493     QCOMPARE(myText->maximumLineCount(), INT_MAX);
1494
1495     myText->setMaximumLineCount(2);
1496     QCOMPARE(myText->lineCount(), 2);
1497     QCOMPARE(myText->truncated(), true);
1498     QCOMPARE(myText->maximumLineCount(), 2);
1499
1500     myText->resetMaximumLineCount();
1501     QCOMPARE(myText->maximumLineCount(), INT_MAX);
1502     QCOMPARE(myText->truncated(), false);
1503
1504     myText->setElideMode(QQuickText::ElideRight);
1505     myText->setMaximumLineCount(2);
1506     QCOMPARE(myText->lineCount(), 2);
1507     QCOMPARE(myText->truncated(), true);
1508     QCOMPARE(myText->maximumLineCount(), 2);
1509
1510     delete canvas;
1511 }
1512
1513 void tst_qquicktext::lineHeight()
1514 {
1515     QQuickView *canvas = createView(testFile("lineHeight.qml"));
1516
1517     QQuickText *myText = canvas->rootObject()->findChild<QQuickText*>("myText");
1518     QVERIFY(myText != 0);
1519
1520     QVERIFY(myText->lineHeight() == 1);
1521     QVERIFY(myText->lineHeightMode() == QQuickText::ProportionalHeight);
1522
1523     qreal h = myText->height();
1524     myText->setLineHeight(1.5);
1525     QCOMPARE(myText->height(), qreal(qCeil(h * 1.5)));
1526
1527     myText->setLineHeightMode(QQuickText::FixedHeight);
1528     myText->setLineHeight(20);
1529     QCOMPARE(myText->height(), myText->lineCount() * 20.0);
1530
1531     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.");
1532     myText->setLineHeightMode(QQuickText::ProportionalHeight);
1533     myText->setLineHeight(1.0);
1534
1535     qreal h2 = myText->height();
1536     myText->setLineHeight(2.0);
1537     QVERIFY(myText->height() == h2 * 2.0);
1538
1539     myText->setLineHeightMode(QQuickText::FixedHeight);
1540     myText->setLineHeight(10);
1541     QCOMPARE(myText->height(), myText->lineCount() * 10.0);
1542
1543     delete canvas;
1544 }
1545
1546 void tst_qquicktext::implicitSize_data()
1547 {
1548     QTest::addColumn<QString>("text");
1549     QTest::addColumn<QString>("width");
1550     QTest::addColumn<QString>("wrap");
1551     QTest::addColumn<QString>("elide");
1552     QTest::newRow("plain") << "The quick red fox jumped over the lazy brown dog" << "50" << "Text.NoWrap" << "Text.ElideNone";
1553     QTest::newRow("richtext") << "<b>The quick red fox jumped over the lazy brown dog</b>" <<" 50" << "Text.NoWrap" << "Text.ElideNone";
1554     QTest::newRow("plain, 0 width") << "The quick red fox jumped over the lazy brown dog" << "0" << "Text.NoWrap" << "Text.ElideNone";
1555     QTest::newRow("plain, elide") << "The quick red fox jumped over the lazy brown dog" << "50" << "Text.NoWrap" << "Text.ElideRight";
1556     QTest::newRow("plain, 0 width, elide") << "The quick red fox jumped over the lazy brown dog" << "0" << "Text.NoWrap" << "Text.ElideRight";
1557     QTest::newRow("richtext, 0 width") << "<b>The quick red fox jumped over the lazy brown dog</b>" <<" 0" << "Text.NoWrap" << "Text.ElideNone";
1558     QTest::newRow("plain_wrap") << "The quick red fox jumped over the lazy brown dog" << "50" << "Text.Wrap" << "Text.ElideNone";
1559     QTest::newRow("richtext_wrap") << "<b>The quick red fox jumped over the lazy brown dog</b>" << "50" << "Text.Wrap" << "Text.ElideNone";
1560     QTest::newRow("plain_wrap, 0 width") << "The quick red fox jumped over the lazy brown dog" << "0" << "Text.Wrap" << "Text.ElideNone";
1561     QTest::newRow("plain_wrap, elide") << "The quick red fox jumped over the lazy brown dog" << "50" << "Text.Wrap" << "Text.ElideRight";
1562     QTest::newRow("plain_wrap, 0 width, elide") << "The quick red fox jumped over the lazy brown dog" << "0" << "Text.Wrap" << "Text.ElideRight";
1563     QTest::newRow("richtext_wrap, 0 width") << "<b>The quick red fox jumped over the lazy brown dog</b>" << "0" << "Text.Wrap" << "Text.ElideNone";
1564 }
1565
1566 void tst_qquicktext::implicitSize()
1567 {
1568     QFETCH(QString, text);
1569     QFETCH(QString, width);
1570     QFETCH(QString, wrap);
1571     QFETCH(QString, elide);
1572     QString componentStr = "import QtQuick 2.0\nText { "
1573             "text: \"" + text + "\"; "
1574             "width: " + width + "; "
1575             "wrapMode: " + wrap + "; "
1576             "elide: " + elide + "; "
1577             "maximumLineCount: 1 }";
1578     QQmlComponent textComponent(&engine);
1579     textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1580     QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1581
1582     QVERIFY(textObject->width() < textObject->implicitWidth());
1583     QVERIFY(textObject->height() == textObject->implicitHeight());
1584
1585     textObject->resetWidth();
1586     QVERIFY(textObject->width() == textObject->implicitWidth());
1587     QVERIFY(textObject->height() == textObject->implicitHeight());
1588
1589     delete textObject;
1590 }
1591
1592 void tst_qquicktext::contentSize()
1593 {
1594     QString componentStr = "import QtQuick 2.0\nText { width: 75; height: 16; font.pixelSize: 10 }";
1595     QQmlComponent textComponent(&engine);
1596     textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1597     QScopedPointer<QObject> object(textComponent.create());
1598     QQuickText *textObject = qobject_cast<QQuickText *>(object.data());
1599
1600     QSignalSpy spy(textObject, SIGNAL(contentSizeChanged()));
1601
1602     textObject->setText("The quick red fox jumped over the lazy brown dog");
1603
1604     QVERIFY(textObject->contentWidth() > textObject->width());
1605     QVERIFY(textObject->contentHeight() < textObject->height());
1606     QCOMPARE(spy.count(), 1);
1607
1608     textObject->setWrapMode(QQuickText::WordWrap);
1609     QVERIFY(textObject->contentWidth() <= textObject->width());
1610     QVERIFY(textObject->contentHeight() > textObject->height());
1611     QCOMPARE(spy.count(), 2);
1612
1613     textObject->setElideMode(QQuickText::ElideRight);
1614     QVERIFY(textObject->contentWidth() <= textObject->width());
1615     QVERIFY(textObject->contentHeight() < textObject->height());
1616     QCOMPARE(spy.count(), 3);
1617     int spyCount = 3;
1618     qreal elidedWidth = textObject->contentWidth();
1619
1620     textObject->setText("The quickredfoxjumpedoverthe lazy brown dog");
1621     QVERIFY(textObject->contentWidth() <= textObject->width());
1622     QVERIFY(textObject->contentHeight() < textObject->height());
1623     // this text probably won't have the same elided width, but it's not guaranteed.
1624     if (textObject->contentWidth() != elidedWidth)
1625         QCOMPARE(spy.count(), ++spyCount);
1626     else
1627         QCOMPARE(spy.count(), spyCount);
1628
1629     textObject->setElideMode(QQuickText::ElideNone);
1630     QVERIFY(textObject->contentWidth() > textObject->width());
1631     QVERIFY(textObject->contentHeight() > textObject->height());
1632     QCOMPARE(spy.count(), ++spyCount);
1633 }
1634
1635 void tst_qquicktext::lineLaidOut()
1636 {
1637     QQuickView *canvas = createView(testFile("lineLayout.qml"));
1638
1639     QQuickText *myText = canvas->rootObject()->findChild<QQuickText*>("myText");
1640     QVERIFY(myText != 0);
1641
1642     QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(myText);
1643     QVERIFY(textPrivate != 0);
1644
1645     QVERIFY(!textPrivate->extra.isAllocated());
1646
1647 #if defined(Q_OS_MAC)
1648     QVERIFY(myText->lineCount() == textPrivate->linesRects.count());
1649 #endif
1650
1651     for (int i = 0; i < textPrivate->layout.lineCount(); ++i) {
1652         QRectF r = textPrivate->layout.lineAt(i).rect();
1653         QVERIFY(r.width() == i * 15);
1654         if (i >= 30)
1655             QVERIFY(r.x() == r.width() + 30);
1656         if (i >= 60) {
1657             QVERIFY(r.x() == r.width() * 2 + 60);
1658             QVERIFY(r.height() == 20);
1659         }
1660     }
1661
1662     delete canvas;
1663 }
1664
1665 void tst_qquicktext::imgTagsBaseUrl_data()
1666 {
1667     QTest::addColumn<QUrl>("src");
1668     QTest::addColumn<QUrl>("baseUrl");
1669     QTest::addColumn<QUrl>("contextUrl");
1670     QTest::addColumn<qreal>("imgHeight");
1671
1672     QTest::newRow("absolute local")
1673             << testFileUrl("images/heart200.png")
1674             << QUrl()
1675             << QUrl()
1676             << 181.;
1677     QTest::newRow("relative local context 1")
1678             << QUrl("images/heart200.png")
1679             << QUrl()
1680             << testFileUrl("/app.qml")
1681             << 181.;
1682     QTest::newRow("relative local context 2")
1683             << QUrl("heart200.png")
1684             << QUrl()
1685             << testFileUrl("images/app.qml")
1686             << 181.;
1687     QTest::newRow("relative local base 1")
1688             << QUrl("images/heart200.png")
1689             << testFileUrl("")
1690             << testFileUrl("nonexistant/app.qml")
1691             << 181.;
1692     QTest::newRow("relative local base 2")
1693             << QUrl("heart200.png")
1694             << testFileUrl("images/")
1695             << testFileUrl("nonexistant/app.qml")
1696             << 181.;
1697     QTest::newRow("base relative to local context")
1698             << QUrl("heart200.png")
1699             << testFileUrl("images/")
1700             << testFileUrl("/app.qml")
1701             << 181.;
1702
1703     QTest::newRow("absolute remote")
1704             << QUrl("http://127.0.0.1:14453/images/heart200.png")
1705             << QUrl()
1706             << QUrl()
1707             << 181.;
1708     QTest::newRow("relative remote base 1")
1709             << QUrl("images/heart200.png")
1710             << QUrl("http://127.0.0.1:14453/")
1711             << testFileUrl("nonexistant/app.qml")
1712             << 181.;
1713     QTest::newRow("relative remote base 2")
1714             << QUrl("heart200.png")
1715             << QUrl("http://127.0.0.1:14453/images/")
1716             << testFileUrl("nonexistant/app.qml")
1717             << 181.;
1718 }
1719
1720 void tst_qquicktext::imgTagsBaseUrl()
1721 {
1722     QFETCH(QUrl, src);
1723     QFETCH(QUrl, baseUrl);
1724     QFETCH(QUrl, contextUrl);
1725     QFETCH(qreal, imgHeight);
1726
1727     TestHTTPServer server(14453);
1728     server.serveDirectory(testFile(""));
1729
1730     QByteArray baseUrlFragment;
1731     if (!baseUrl.isEmpty())
1732         baseUrlFragment = "; baseUrl: \"" + baseUrl.toEncoded() + "\"";
1733     QByteArray componentStr = "import QtQuick 2.0\nText { text: \"This is a test <img src=\\\"" + src.toEncoded() + "\\\">\"" + baseUrlFragment + " }";
1734
1735     QQmlComponent component(&engine);
1736     component.setData(componentStr, contextUrl);
1737     QScopedPointer<QObject> object(component.create());
1738     QQuickText *textObject = qobject_cast<QQuickText *>(object.data());
1739     QVERIFY(textObject);
1740
1741     QCoreApplication::processEvents();
1742
1743     QTRY_COMPARE(textObject->height(), imgHeight);
1744 }
1745
1746 void tst_qquicktext::imgTagsAlign_data()
1747 {
1748     QTest::addColumn<QString>("src");
1749     QTest::addColumn<int>("imgHeight");
1750     QTest::addColumn<QString>("align");
1751     QTest::newRow("heart-bottom") << "data/images/heart200.png" << 181 <<  "bottom";
1752     QTest::newRow("heart-middle") << "data/images/heart200.png" << 181 <<  "middle";
1753     QTest::newRow("heart-top") << "data/images/heart200.png" << 181 <<  "top";
1754     QTest::newRow("starfish-bottom") << "data/images/starfish_2.png" << 217 <<  "bottom";
1755     QTest::newRow("starfish-middle") << "data/images/starfish_2.png" << 217 <<  "middle";
1756     QTest::newRow("starfish-top") << "data/images/starfish_2.png" << 217 <<  "top";
1757 }
1758
1759 void tst_qquicktext::imgTagsAlign()
1760 {
1761     QFETCH(QString, src);
1762     QFETCH(int, imgHeight);
1763     QFETCH(QString, align);
1764     QString componentStr = "import QtQuick 2.0\nText { text: \"This is a test <img src=\\\"" + src + "\\\" align=\\\"" + align + "\\\"> of image.\" }";
1765     QQmlComponent textComponent(&engine);
1766     textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1767     QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1768
1769     QVERIFY(textObject != 0);
1770     QVERIFY(textObject->height() == imgHeight);
1771
1772     QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject);
1773     QVERIFY(textPrivate != 0);
1774
1775     QRectF br = textPrivate->layout.boundingRect();
1776     if (align == "bottom")
1777         QVERIFY(br.y() == imgHeight - br.height());
1778     else if (align == "middle")
1779         QVERIFY(br.y() == imgHeight / 2.0 - br.height() / 2.0);
1780     else if (align == "top")
1781         QVERIFY(br.y() == 0);
1782
1783     delete textObject;
1784 }
1785
1786 void tst_qquicktext::imgTagsMultipleImages()
1787 {
1788     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\\\">.\" }";
1789
1790     QQmlComponent textComponent(&engine);
1791     textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1792     QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1793
1794     QVERIFY(textObject != 0);
1795     QVERIFY(textObject->height() == 85);
1796
1797     QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject);
1798     QVERIFY(textPrivate != 0);
1799     QVERIFY(textPrivate->visibleImgTags.count() == 2);
1800
1801     delete textObject;
1802 }
1803
1804 void tst_qquicktext::imgTagsElide()
1805 {
1806     QQuickView *canvas = createView(testFile("imgTagsElide.qml"));
1807     QQuickText *myText = canvas->rootObject()->findChild<QQuickText*>("myText");
1808     QVERIFY(myText != 0);
1809
1810     QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(myText);
1811     QVERIFY(textPrivate != 0);
1812     QVERIFY(textPrivate->visibleImgTags.count() == 0);
1813     myText->setMaximumLineCount(20);
1814     QTRY_VERIFY(textPrivate->visibleImgTags.count() == 1);
1815
1816     delete myText;
1817     delete canvas;
1818 }
1819
1820 void tst_qquicktext::imgTagsUpdates()
1821 {
1822     QQuickView *canvas = createView(testFile("imgTagsUpdates.qml"));
1823     QQuickText *myText = canvas->rootObject()->findChild<QQuickText*>("myText");
1824     QVERIFY(myText != 0);
1825
1826     QSignalSpy spy(myText, SIGNAL(contentSizeChanged()));
1827
1828     QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(myText);
1829     QVERIFY(textPrivate != 0);
1830
1831     myText->setText("This is a heart<img src=\"images/heart200.png\">.");
1832     QVERIFY(textPrivate->visibleImgTags.count() == 1);
1833     QVERIFY(spy.count() == 1);
1834
1835     myText->setMaximumLineCount(2);
1836     myText->setText("This is another heart<img src=\"images/heart200.png\">.");
1837     QTRY_VERIFY(textPrivate->visibleImgTags.count() == 1);
1838
1839     // if maximumLineCount is set and the img tag doesn't have an explicit size
1840     // we relayout twice.
1841     QVERIFY(spy.count() == 3);
1842
1843     delete myText;
1844     delete canvas;
1845 }
1846
1847 void tst_qquicktext::imgTagsError()
1848 {
1849     QString componentStr = "import QtQuick 2.0\nText { text: \"This is a starfish<img src=\\\"data/images/starfish_2.pn\\\" width=\\\"60\\\" height=\\\"60\\\">.\" }";
1850
1851     QQmlComponent textComponent(&engine);
1852     QTest::ignoreMessage(QtWarningMsg, "file::2:1: QML Text: Cannot open: file:data/images/starfish_2.pn");
1853     textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1854     QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1855
1856     QVERIFY(textObject != 0);
1857     delete textObject;
1858 }
1859
1860 void tst_qquicktext::fontSizeMode_data()
1861 {
1862     QTest::addColumn<QString>("text");
1863     QTest::newRow("plain") << "The quick red fox jumped over the lazy brown dog";
1864     QTest::newRow("styled") << "<b>The quick red fox jumped over the lazy brown dog</b>";
1865 }
1866
1867 void tst_qquicktext::fontSizeMode()
1868 {
1869     QFETCH(QString, text);
1870
1871     QScopedPointer<QQuickView> canvas(createView(testFile("fontSizeMode.qml")));
1872     canvas->show();
1873
1874     QQuickText *myText = canvas->rootObject()->findChild<QQuickText*>("myText");
1875     QVERIFY(myText != 0);
1876
1877     myText->setText(text);
1878     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
1879
1880     qreal originalWidth = myText->contentWidth();
1881     qreal originalHeight = myText->contentHeight();
1882
1883     // The original text unwrapped should exceed the width of the item.
1884     QVERIFY(originalWidth > myText->width());
1885     QVERIFY(originalHeight < myText->height());
1886
1887     QFont font = myText->font();
1888     font.setPixelSize(64);
1889
1890     myText->setFont(font);
1891     myText->setFontSizeMode(QQuickText::HorizontalFit);
1892     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
1893     // Font size reduced to fit within the width of the item.
1894     qreal horizontalFitWidth = myText->contentWidth();
1895     qreal horizontalFitHeight = myText->contentHeight();
1896     QVERIFY(horizontalFitWidth <= myText->width() + 2); // rounding
1897     QVERIFY(horizontalFitHeight <= myText->height() + 2);
1898
1899     // Elide won't affect the size with HorizontalFit.
1900     myText->setElideMode(QQuickText::ElideRight);
1901     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
1902     QVERIFY(!myText->truncated());
1903     QCOMPARE(myText->contentWidth(), horizontalFitWidth);
1904     QCOMPARE(myText->contentHeight(), horizontalFitHeight);
1905
1906     myText->setElideMode(QQuickText::ElideLeft);
1907     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
1908     QVERIFY(!myText->truncated());
1909     QCOMPARE(myText->contentWidth(), horizontalFitWidth);
1910     QCOMPARE(myText->contentHeight(), horizontalFitHeight);
1911
1912     myText->setElideMode(QQuickText::ElideMiddle);
1913     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
1914     QVERIFY(!myText->truncated());
1915     QCOMPARE(myText->contentWidth(), horizontalFitWidth);
1916     QCOMPARE(myText->contentHeight(), horizontalFitHeight);
1917
1918     myText->setElideMode(QQuickText::ElideNone);
1919     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
1920
1921     myText->setFontSizeMode(QQuickText::VerticalFit);
1922     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
1923     // Font size increased to fill the height of the item.
1924     qreal verticalFitHeight = myText->contentHeight();
1925     QVERIFY(myText->contentWidth() > myText->width());
1926     QVERIFY(verticalFitHeight <= myText->height() + 2);
1927     QVERIFY(verticalFitHeight > originalHeight);
1928
1929     // Elide won't affect the height of a single line with VerticalFit but will crop the width.
1930     myText->setElideMode(QQuickText::ElideRight);
1931     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
1932     QVERIFY(myText->truncated());
1933     QVERIFY(myText->contentWidth() <= myText->width() + 2);
1934     QCOMPARE(myText->contentHeight(), verticalFitHeight);
1935
1936     myText->setElideMode(QQuickText::ElideLeft);
1937     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
1938     QVERIFY(myText->truncated());
1939     QVERIFY(myText->contentWidth() <= myText->width() + 2);
1940     QCOMPARE(myText->contentHeight(), verticalFitHeight);
1941
1942     myText->setElideMode(QQuickText::ElideMiddle);
1943     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
1944     QVERIFY(myText->truncated());
1945     QVERIFY(myText->contentWidth() <= myText->width() + 2);
1946     QCOMPARE(myText->contentHeight(), verticalFitHeight);
1947
1948     myText->setElideMode(QQuickText::ElideNone);
1949     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
1950
1951     myText->setFontSizeMode(QQuickText::Fit);
1952     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
1953     // Should be the same as HorizontalFit with no wrapping.
1954     QCOMPARE(myText->contentWidth(), horizontalFitWidth);
1955     QCOMPARE(myText->contentHeight(), horizontalFitHeight);
1956
1957     // Elide won't affect the size with Fit.
1958     myText->setElideMode(QQuickText::ElideRight);
1959     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
1960     QVERIFY(!myText->truncated());
1961     QCOMPARE(myText->contentWidth(), horizontalFitWidth);
1962     QCOMPARE(myText->contentHeight(), horizontalFitHeight);
1963
1964     myText->setElideMode(QQuickText::ElideLeft);
1965     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
1966     QVERIFY(!myText->truncated());
1967     QCOMPARE(myText->contentWidth(), horizontalFitWidth);
1968     QCOMPARE(myText->contentHeight(), horizontalFitHeight);
1969
1970     myText->setElideMode(QQuickText::ElideMiddle);
1971     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
1972     QVERIFY(!myText->truncated());
1973     QCOMPARE(myText->contentWidth(), horizontalFitWidth);
1974     QCOMPARE(myText->contentHeight(), horizontalFitHeight);
1975
1976     myText->setElideMode(QQuickText::ElideNone);
1977     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
1978
1979     myText->setFontSizeMode(QQuickText::FixedSize);
1980     myText->setWrapMode(QQuickText::Wrap);
1981     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
1982
1983     originalWidth = myText->contentWidth();
1984     originalHeight = myText->contentHeight();
1985
1986     // The original text wrapped should exceed the height of the item.
1987     QVERIFY(originalWidth <= myText->width() + 2);
1988     QVERIFY(originalHeight > myText->height());
1989
1990     myText->setFontSizeMode(QQuickText::HorizontalFit);
1991     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
1992     // HorizontalFit should reduce the font size to minimize wrapping, which brings it back to the
1993     // same size as without text wrapping.
1994     QCOMPARE(myText->contentWidth(), horizontalFitWidth);
1995     QCOMPARE(myText->contentHeight(), horizontalFitHeight);
1996
1997     // Elide won't affect the size with HorizontalFit.
1998     myText->setElideMode(QQuickText::ElideRight);
1999     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2000     QVERIFY(!myText->truncated());
2001     QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2002     QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2003
2004     myText->setElideMode(QQuickText::ElideNone);
2005     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2006
2007     myText->setFontSizeMode(QQuickText::VerticalFit);
2008     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2009     // VerticalFit should reduce the size to the wrapped text within the vertical height.
2010     verticalFitHeight = myText->contentHeight();
2011     qreal verticalFitWidth = myText->contentWidth();
2012     QVERIFY(myText->contentWidth() <= myText->width() + 2);
2013     QVERIFY(verticalFitHeight <= myText->height() + 2);
2014     QVERIFY(verticalFitHeight < originalHeight);
2015
2016     // Elide won't affect the height or width of a wrapped text with VerticalFit.
2017     myText->setElideMode(QQuickText::ElideRight);
2018     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2019     QVERIFY(!myText->truncated());
2020     QCOMPARE(myText->contentWidth(), verticalFitWidth);
2021     QCOMPARE(myText->contentHeight(), verticalFitHeight);
2022
2023     myText->setElideMode(QQuickText::ElideNone);
2024     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2025
2026     myText->setFontSizeMode(QQuickText::Fit);
2027     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2028     // Should be the same as VerticalFit with wrapping.
2029     QCOMPARE(myText->contentWidth(), verticalFitWidth);
2030     QCOMPARE(myText->contentHeight(), verticalFitHeight);
2031
2032     // Elide won't affect the size with Fit.
2033     myText->setElideMode(QQuickText::ElideRight);
2034     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2035     QVERIFY(!myText->truncated());
2036     QCOMPARE(myText->contentWidth(), verticalFitWidth);
2037     QCOMPARE(myText->contentHeight(), verticalFitHeight);
2038
2039     myText->setElideMode(QQuickText::ElideNone);
2040     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2041
2042     myText->setFontSizeMode(QQuickText::FixedSize);
2043     myText->setMaximumLineCount(2);
2044     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2045
2046     // The original text wrapped should exceed the height of the item.
2047     QVERIFY(originalWidth <= myText->width() + 2);
2048     QVERIFY(originalHeight > myText->height());
2049
2050     myText->setFontSizeMode(QQuickText::HorizontalFit);
2051     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2052     // HorizontalFit should reduce the font size to minimize wrapping, which brings it back to the
2053     // same size as without text wrapping.
2054     QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2055     QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2056
2057     // Elide won't affect the size with HorizontalFit.
2058     myText->setElideMode(QQuickText::ElideRight);
2059     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2060     QVERIFY(!myText->truncated());
2061     QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2062     QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2063
2064     myText->setElideMode(QQuickText::ElideNone);
2065     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2066
2067     myText->setFontSizeMode(QQuickText::VerticalFit);
2068     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2069     // VerticalFit should reduce the size to the wrapped text within the vertical height.
2070     verticalFitHeight = myText->contentHeight();
2071     verticalFitWidth = myText->contentWidth();
2072     QVERIFY(myText->contentWidth() <= myText->width() + 2);
2073     QVERIFY(verticalFitHeight <= myText->height() + 2);
2074     QVERIFY(verticalFitHeight < originalHeight);
2075
2076     // Elide won't affect the height or width of a wrapped text with VerticalFit.
2077     myText->setElideMode(QQuickText::ElideRight);
2078     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2079     QVERIFY(!myText->truncated());
2080     QCOMPARE(myText->contentWidth(), verticalFitWidth);
2081     QCOMPARE(myText->contentHeight(), verticalFitHeight);
2082
2083     myText->setElideMode(QQuickText::ElideNone);
2084     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2085
2086     myText->setFontSizeMode(QQuickText::Fit);
2087     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2088     // Should be the same as VerticalFit with wrapping.
2089     QCOMPARE(myText->contentWidth(), verticalFitWidth);
2090     QCOMPARE(myText->contentHeight(), verticalFitHeight);
2091
2092     // Elide won't affect the size with Fit.
2093     myText->setElideMode(QQuickText::ElideRight);
2094     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2095     QVERIFY(!myText->truncated());
2096     QCOMPARE(myText->contentWidth(), verticalFitWidth);
2097     QCOMPARE(myText->contentHeight(), verticalFitHeight);
2098
2099     myText->setElideMode(QQuickText::ElideNone);
2100     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2101 }
2102
2103 void tst_qquicktext::fontSizeModeMultiline_data()
2104 {
2105     QTest::addColumn<QString>("text");
2106     QTest::newRow("plain") << "The quick red fox jumped\n over the lazy brown dog";
2107     QTest::newRow("styledtext") << "<b>The quick red fox jumped<br/> over the lazy brown dog</b>";
2108 }
2109
2110 void tst_qquicktext::fontSizeModeMultiline()
2111 {
2112     QFETCH(QString, text);
2113
2114     QScopedPointer<QQuickView> canvas(createView(testFile("fontSizeMode.qml")));
2115     canvas->show();
2116
2117     QQuickText *myText = canvas->rootObject()->findChild<QQuickText*>("myText");
2118     QVERIFY(myText != 0);
2119
2120     myText->setText(text);
2121     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2122
2123     qreal originalWidth = myText->contentWidth();
2124     qreal originalHeight = myText->contentHeight();
2125     QCOMPARE(myText->lineCount(), 2);
2126
2127     // The original text unwrapped should exceed the width and height of the item.
2128     QVERIFY(originalWidth > myText->width());
2129     QVERIFY(originalHeight > myText->height());
2130
2131     QFont font = myText->font();
2132     font.setPixelSize(64);
2133
2134     myText->setFont(font);
2135     myText->setFontSizeMode(QQuickText::HorizontalFit);
2136     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2137     // Font size reduced to fit within the width of the item.
2138     QCOMPARE(myText->lineCount(), 2);
2139     qreal horizontalFitWidth = myText->contentWidth();
2140     qreal horizontalFitHeight = myText->contentHeight();
2141     QVERIFY(horizontalFitWidth <= myText->width() + 2); // rounding
2142     QVERIFY(horizontalFitHeight > myText->height());
2143
2144     // Right eliding will remove the last line
2145     myText->setElideMode(QQuickText::ElideRight);
2146     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2147     QVERIFY(myText->truncated());
2148     QCOMPARE(myText->lineCount(), 1);
2149     QVERIFY(myText->contentWidth() <= myText->width() + 2);
2150     QVERIFY(myText->contentHeight() <= myText->height() + 2);
2151
2152     // Left or middle eliding wont have any effect.
2153     myText->setElideMode(QQuickText::ElideLeft);
2154     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2155     QVERIFY(!myText->truncated());
2156     QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2157     QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2158
2159     myText->setElideMode(QQuickText::ElideMiddle);
2160     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2161     QVERIFY(!myText->truncated());
2162     QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2163     QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2164
2165     myText->setElideMode(QQuickText::ElideNone);
2166     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2167
2168     myText->setFontSizeMode(QQuickText::VerticalFit);
2169     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2170     // Font size reduced to fit within the height of the item.
2171     qreal verticalFitWidth = myText->contentWidth();
2172     qreal verticalFitHeight = myText->contentHeight();
2173     QVERIFY(verticalFitWidth <= myText->width() + 2);
2174     QVERIFY(verticalFitHeight <= myText->height() + 2);
2175
2176     // Elide will have no effect.
2177     myText->setElideMode(QQuickText::ElideRight);
2178     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2179     QVERIFY(!myText->truncated());
2180     QVERIFY(myText->contentWidth() <= myText->width() + 2);
2181     QCOMPARE(myText->contentWidth(), verticalFitWidth);
2182     QCOMPARE(myText->contentHeight(), verticalFitHeight);
2183
2184     myText->setElideMode(QQuickText::ElideLeft);
2185     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2186     QVERIFY(!myText->truncated());
2187     QCOMPARE(myText->contentWidth(), verticalFitWidth);
2188     QCOMPARE(myText->contentHeight(), verticalFitHeight);
2189
2190     myText->setElideMode(QQuickText::ElideMiddle);
2191     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2192     QVERIFY(!myText->truncated());
2193     QCOMPARE(myText->contentWidth(), verticalFitWidth);
2194     QCOMPARE(myText->contentHeight(), verticalFitHeight);
2195
2196     myText->setElideMode(QQuickText::ElideNone);
2197     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2198
2199     myText->setFontSizeMode(QQuickText::Fit);
2200     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2201     // Should be the same as VerticalFit with no wrapping.
2202     QCOMPARE(myText->contentWidth(), verticalFitWidth);
2203     QCOMPARE(myText->contentHeight(), verticalFitHeight);
2204
2205     // Elide won't affect the size with Fit.
2206     myText->setElideMode(QQuickText::ElideRight);
2207     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2208     QVERIFY(!myText->truncated());
2209     QCOMPARE(myText->contentWidth(), verticalFitWidth);
2210     QCOMPARE(myText->contentHeight(), verticalFitHeight);
2211
2212     myText->setElideMode(QQuickText::ElideLeft);
2213     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2214     QVERIFY(!myText->truncated());
2215     QCOMPARE(myText->contentWidth(), verticalFitWidth);
2216     QCOMPARE(myText->contentHeight(), verticalFitHeight);
2217
2218     myText->setElideMode(QQuickText::ElideMiddle);
2219     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2220     QVERIFY(!myText->truncated());
2221     QCOMPARE(myText->contentWidth(), verticalFitWidth);
2222     QCOMPARE(myText->contentHeight(), verticalFitHeight);
2223
2224     myText->setElideMode(QQuickText::ElideNone);
2225     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2226
2227     myText->setFontSizeMode(QQuickText::FixedSize);
2228     myText->setWrapMode(QQuickText::Wrap);
2229     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2230
2231     originalWidth = myText->contentWidth();
2232     originalHeight = myText->contentHeight();
2233
2234     // The original text wrapped should exceed the height of the item.
2235     QVERIFY(originalWidth <= myText->width() + 2);
2236     QVERIFY(originalHeight > myText->height());
2237
2238     myText->setFontSizeMode(QQuickText::HorizontalFit);
2239     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2240     // HorizontalFit should reduce the font size to minimize wrapping, which brings it back to the
2241     // same size as without text wrapping.
2242     QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2243     QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2244
2245     // Text will be elided vertically with HorizontalFit
2246     myText->setElideMode(QQuickText::ElideRight);
2247     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2248     QVERIFY(myText->truncated());
2249     QVERIFY(myText->contentWidth() <= myText->width() + 2);
2250     QVERIFY(myText->contentHeight() <= myText->height() + 2);
2251
2252     myText->setElideMode(QQuickText::ElideNone);
2253     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2254
2255     myText->setFontSizeMode(QQuickText::VerticalFit);
2256     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2257     // VerticalFit should reduce the size to the wrapped text within the vertical height.
2258     verticalFitHeight = myText->contentHeight();
2259     verticalFitWidth = myText->contentWidth();
2260     QVERIFY(myText->contentWidth() <= myText->width() + 2);
2261     QVERIFY(verticalFitHeight <= myText->height() + 2);
2262     QVERIFY(verticalFitHeight < originalHeight);
2263
2264     // Elide won't affect the height or width of a wrapped text with VerticalFit.
2265     myText->setElideMode(QQuickText::ElideRight);
2266     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2267     QVERIFY(!myText->truncated());
2268     QCOMPARE(myText->contentWidth(), verticalFitWidth);
2269     QCOMPARE(myText->contentHeight(), verticalFitHeight);
2270
2271     myText->setElideMode(QQuickText::ElideNone);
2272     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2273
2274     myText->setFontSizeMode(QQuickText::Fit);
2275     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2276     // Should be the same as VerticalFit with wrapping.
2277     QCOMPARE(myText->contentWidth(), verticalFitWidth);
2278     QCOMPARE(myText->contentHeight(), verticalFitHeight);
2279
2280     // Elide won't affect the size with Fit.
2281     myText->setElideMode(QQuickText::ElideRight);
2282     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2283     QVERIFY(!myText->truncated());
2284     QCOMPARE(myText->contentWidth(), verticalFitWidth);
2285     QCOMPARE(myText->contentHeight(), verticalFitHeight);
2286
2287     myText->setElideMode(QQuickText::ElideNone);
2288     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2289
2290     myText->setFontSizeMode(QQuickText::FixedSize);
2291     myText->setMaximumLineCount(2);
2292     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2293
2294     // The original text wrapped should exceed the height of the item.
2295     QVERIFY(originalWidth <= myText->width() + 2);
2296     QVERIFY(originalHeight > myText->height());
2297
2298     myText->setFontSizeMode(QQuickText::HorizontalFit);
2299     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2300     // HorizontalFit should reduce the font size to minimize wrapping, which brings it back to the
2301     // same size as without text wrapping.
2302     QCOMPARE(myText->contentWidth(), horizontalFitWidth);
2303     QCOMPARE(myText->contentHeight(), horizontalFitHeight);
2304
2305     // Elide won't affect the size with HorizontalFit.
2306     myText->setElideMode(QQuickText::ElideRight);
2307     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2308     QVERIFY(myText->truncated());
2309     QVERIFY(myText->contentWidth() <= myText->width() + 2);
2310     QVERIFY(myText->contentHeight() <= myText->height() + 2);
2311
2312     myText->setElideMode(QQuickText::ElideNone);
2313     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2314
2315     myText->setFontSizeMode(QQuickText::VerticalFit);
2316     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2317     // VerticalFit should reduce the size to the wrapped text within the vertical height.
2318     verticalFitHeight = myText->contentHeight();
2319     verticalFitWidth = myText->contentWidth();
2320     QVERIFY(myText->contentWidth() <= myText->width() + 2);
2321     QVERIFY(verticalFitHeight <= myText->height() + 2);
2322     QVERIFY(verticalFitHeight < originalHeight);
2323
2324     // Elide won't affect the height or width of a wrapped text with VerticalFit.
2325     myText->setElideMode(QQuickText::ElideRight);
2326     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2327     QVERIFY(!myText->truncated());
2328     QCOMPARE(myText->contentWidth(), verticalFitWidth);
2329     QCOMPARE(myText->contentHeight(), verticalFitHeight);
2330
2331     myText->setElideMode(QQuickText::ElideNone);
2332     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2333
2334     myText->setFontSizeMode(QQuickText::Fit);
2335     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2336     // Should be the same as VerticalFit with wrapping.
2337     QCOMPARE(myText->contentWidth(), verticalFitWidth);
2338     QCOMPARE(myText->contentHeight(), verticalFitHeight);
2339
2340     // Elide won't affect the size with Fit.
2341     myText->setElideMode(QQuickText::ElideRight);
2342     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2343     QVERIFY(!myText->truncated());
2344     QCOMPARE(myText->contentWidth(), verticalFitWidth);
2345     QCOMPARE(myText->contentHeight(), verticalFitHeight);
2346
2347     myText->setElideMode(QQuickText::ElideNone);
2348     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2349 }
2350
2351 void tst_qquicktext::multilengthStrings_data()
2352 {
2353     QTest::addColumn<QString>("source");
2354     QTest::newRow("No Wrap") << testFile("multilengthStrings.qml");
2355     QTest::newRow("Wrap") << testFile("multilengthStringsWrapped.qml");
2356 }
2357
2358 void tst_qquicktext::multilengthStrings()
2359 {
2360     QFETCH(QString, source);
2361
2362     QScopedPointer<QQuickView> canvas(createView(source));
2363     canvas->show();
2364
2365     QQuickText *myText = canvas->rootObject()->findChild<QQuickText*>("myText");
2366     QVERIFY(myText != 0);
2367
2368     const QString longText = "the quick brown fox jumped over the lazy dog";
2369     const QString mediumText = "the brown fox jumped over the dog";
2370     const QString shortText = "fox jumped dog";
2371
2372     myText->setText(longText);
2373     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2374     const qreal longWidth = myText->contentWidth();
2375     const qreal longHeight = myText->contentHeight();
2376
2377     myText->setText(mediumText);
2378     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2379     const qreal mediumWidth = myText->contentWidth();
2380     const qreal mediumHeight = myText->contentHeight();
2381
2382     myText->setText(shortText);
2383     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2384     const qreal shortWidth = myText->contentWidth();
2385     const qreal shortHeight = myText->contentHeight();
2386
2387     myText->setElideMode(QQuickText::ElideRight);
2388     myText->setText(longText + QLatin1Char('\x9c') + mediumText + QLatin1Char('\x9c') + shortText);
2389
2390     myText->setSize(QSizeF(longWidth, longHeight));
2391     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2392
2393     QCOMPARE(myText->contentWidth(), longWidth);
2394     QCOMPARE(myText->contentHeight(), longHeight);
2395     QCOMPARE(myText->truncated(), false);
2396
2397     myText->setSize(QSizeF(mediumWidth, mediumHeight));
2398     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2399
2400     QCOMPARE(myText->contentWidth(), mediumWidth);
2401     QCOMPARE(myText->contentHeight(), mediumHeight);
2402     QCOMPARE(myText->truncated(), true);
2403
2404     myText->setSize(QSizeF(shortWidth, shortHeight));
2405     QTRY_COMPARE(QQuickItemPrivate::get(myText)->polishScheduled, false);
2406
2407     QCOMPARE(myText->contentWidth(), shortWidth);
2408     QCOMPARE(myText->contentHeight(), shortHeight);
2409     QCOMPARE(myText->truncated(), true);
2410 }
2411
2412 void tst_qquicktext::fontFormatSizes_data()
2413 {
2414     QTest::addColumn<QString>("text");
2415     QTest::addColumn<QString>("textWithTag");
2416     QTest::addColumn<bool>("fontIsBigger");
2417
2418     QTest::newRow("fs1") << "Hello world!" << "Hello <font size=\"1\">world</font>!" << false;
2419     QTest::newRow("fs2") << "Hello world!" << "Hello <font size=\"2\">world</font>!" << false;
2420     QTest::newRow("fs3") << "Hello world!" << "Hello <font size=\"3\">world</font>!" << false;
2421     QTest::newRow("fs4") << "Hello world!" << "Hello <font size=\"4\">world</font>!" << true;
2422     QTest::newRow("fs5") << "Hello world!" << "Hello <font size=\"5\">world</font>!" << true;
2423     QTest::newRow("fs6") << "Hello world!" << "Hello <font size=\"6\">world</font>!" << true;
2424     QTest::newRow("fs7") << "Hello world!" << "Hello <font size=\"7\">world</font>!" << true;
2425     QTest::newRow("h1") << "This is<br/>a font<br/> size test." << "This is <h1>a font</h1> size test." << true;
2426     QTest::newRow("h2") << "This is<br/>a font<br/> size test." << "This is <h2>a font</h2> size test." << true;
2427     QTest::newRow("h3") << "This is<br/>a font<br/> size test." << "This is <h3>a font</h3> size test." << true;
2428     QTest::newRow("h4") << "This is<br/>a font<br/> size test." << "This is <h4>a font</h4> size test." << true;
2429     QTest::newRow("h5") << "This is<br/>a font<br/> size test." << "This is <h5>a font</h5> size test." << false;
2430     QTest::newRow("h6") << "This is<br/>a font<br/> size test." << "This is <h6>a font</h6> size test." << false;
2431 }
2432
2433 void tst_qquicktext::fontFormatSizes()
2434 {
2435     QFETCH(QString, text);
2436     QFETCH(QString, textWithTag);
2437     QFETCH(bool, fontIsBigger);
2438
2439     QQuickView *view = new QQuickView;
2440     {
2441         view->setSource(testFileUrl("pointFontSizes.qml"));
2442         view->show();
2443
2444         QQuickText *qtext = view->rootObject()->findChild<QQuickText*>("text");
2445         QQuickText *qtextWithTag = view->rootObject()->findChild<QQuickText*>("textWithTag");
2446         QVERIFY(qtext != 0);
2447         QVERIFY(qtextWithTag != 0);
2448
2449         qtext->setText(text);
2450         qtextWithTag->setText(textWithTag);
2451
2452         for (int size = 6; size < 100; size += 4) {
2453             view->rootObject()->setProperty("pointSize", size);
2454             if (fontIsBigger)
2455                 QVERIFY(qtext->height() <= qtextWithTag->height());
2456             else
2457                 QVERIFY(qtext->height() >= qtextWithTag->height());
2458         }
2459     }
2460
2461     {
2462         view->setSource(testFileUrl("pixelFontSizes.qml"));
2463         QQuickText *qtext = view->rootObject()->findChild<QQuickText*>("text");
2464         QQuickText *qtextWithTag = view->rootObject()->findChild<QQuickText*>("textWithTag");
2465         QVERIFY(qtext != 0);
2466         QVERIFY(qtextWithTag != 0);
2467
2468         qtext->setText(text);
2469         qtextWithTag->setText(textWithTag);
2470
2471         for (int size = 6; size < 100; size += 4) {
2472             view->rootObject()->setProperty("pixelSize", size);
2473             if (fontIsBigger)
2474                 QVERIFY(qtext->height() <= qtextWithTag->height());
2475             else
2476                 QVERIFY(qtext->height() >= qtextWithTag->height());
2477         }
2478     }
2479     delete view;
2480 }
2481
2482 QTEST_MAIN(tst_qquicktext)
2483
2484 #include "tst_qquicktext.moc"