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