Avoid Text layout being triggered unnecessarily
[profile/ivi/qtdeclarative.git] / tests / auto / qtquick2 / qquicktext / tst_qquicktext.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the test suite of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 #include <qtest.h>
42 #include <QTextDocument>
43 #include <QtDeclarative/qdeclarativeengine.h>
44 #include <QtDeclarative/qdeclarativecomponent.h>
45 #include <QtQuick/private/qquicktext_p.h>
46 #include <private/qquicktext_p_p.h>
47 #include <private/qdeclarativevaluetype_p.h>
48 #include <QFontMetrics>
49 #include <QGraphicsSceneMouseEvent>
50 #include <qmath.h>
51 #include <QtQuick/QQuickView>
52 #include <private/qapplication_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 class tst_qquicktext : public QObject
61 {
62     Q_OBJECT
63 public:
64     tst_qquicktext();
65
66 private slots:
67     void initTestCase();
68     void cleanupTestCase();
69     void text();
70     void width();
71     void wrap();
72     void elide();
73     void multilineElide();
74     void textFormat();
75
76     void alignments_data();
77     void alignments();
78
79     void embeddedImages_data();
80     void embeddedImages();
81
82     void lineCount();
83     void lineHeight();
84
85     // ### these tests may be trivial
86     void horizontalAlignment();
87     void horizontalAlignment_RightToLeft();
88     void verticalAlignment();
89     void font();
90     void style();
91     void color();
92     void smooth();
93
94     // QDeclarativeFontValueType
95     void weight();
96     void underline();
97     void overline();
98     void strikeout();
99     void capitalization();
100     void letterSpacing();
101     void wordSpacing();
102
103     void clickLink();
104
105     void implicitSize_data();
106     void implicitSize();
107
108     void lineLaidOut();
109
110
111 private:
112     QStringList standard;
113     QStringList richText;
114
115     QStringList horizontalAlignmentmentStrings;
116     QStringList verticalAlignmentmentStrings;
117
118     QList<Qt::Alignment> verticalAlignmentments;
119     QList<Qt::Alignment> horizontalAlignmentments;
120
121     QStringList styleStrings;
122     QList<QQuickText::TextStyle> styles;
123
124     QStringList colorStrings;
125
126     QDeclarativeEngine engine;
127
128     QQuickView *createView(const QString &filename);
129 };
130 void tst_qquicktext::initTestCase()
131 {
132 }
133
134 void tst_qquicktext::cleanupTestCase()
135 {
136
137 }
138 tst_qquicktext::tst_qquicktext()
139 {
140     standard << "the quick brown fox jumped over the lazy dog"
141             << "the quick brown fox\n jumped over the lazy dog";
142
143     richText << "<i>the <b>quick</b> brown <a href=\\\"http://www.google.com\\\">fox</a> jumped over the <b>lazy</b> dog</i>"
144             << "<i>the <b>quick</b> brown <a href=\\\"http://www.google.com\\\">fox</a><br>jumped over the <b>lazy</b> dog</i>";
145
146     horizontalAlignmentmentStrings << "AlignLeft"
147             << "AlignRight"
148             << "AlignHCenter";
149
150     verticalAlignmentmentStrings << "AlignTop"
151             << "AlignBottom"
152             << "AlignVCenter";
153
154     horizontalAlignmentments << Qt::AlignLeft
155             << Qt::AlignRight
156             << Qt::AlignHCenter;
157
158     verticalAlignmentments << Qt::AlignTop
159             << Qt::AlignBottom
160             << Qt::AlignVCenter;
161
162     styleStrings << "Normal"
163             << "Outline"
164             << "Raised"
165             << "Sunken";
166
167     styles << QQuickText::Normal
168             << QQuickText::Outline
169             << QQuickText::Raised
170             << QQuickText::Sunken;
171
172     colorStrings << "aliceblue"
173             << "antiquewhite"
174             << "aqua"
175             << "darkkhaki"
176             << "darkolivegreen"
177             << "dimgray"
178             << "palevioletred"
179             << "lightsteelblue"
180             << "#000000"
181             << "#AAAAAA"
182             << "#FFFFFF"
183             << "#2AC05F";
184     //
185     // need a different test to do alpha channel test
186     // << "#AA0011DD"
187     // << "#00F16B11";
188     //
189 }
190
191 QQuickView *tst_qquicktext::createView(const QString &filename)
192 {
193     QQuickView *canvas = new QQuickView(0);
194
195     canvas->setSource(QUrl::fromLocalFile(filename));
196     return canvas;
197 }
198
199 void tst_qquicktext::text()
200 {
201     {
202         QDeclarativeComponent textComponent(&engine);
203         textComponent.setData("import QtQuick 2.0\nText { text: \"\" }", QUrl::fromLocalFile(""));
204         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
205
206         QVERIFY(textObject != 0);
207         QCOMPARE(textObject->text(), QString(""));
208         QVERIFY(textObject->width() == 0);
209
210         delete textObject;
211     }
212
213     for (int i = 0; i < standard.size(); i++)
214     {
215         QString componentStr = "import QtQuick 2.0\nText { text: \"" + standard.at(i) + "\" }";
216         QDeclarativeComponent textComponent(&engine);
217         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
218
219         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
220
221         QVERIFY(textObject != 0);
222         QCOMPARE(textObject->text(), standard.at(i));
223         QVERIFY(textObject->width() > 0);
224
225         delete textObject;
226     }
227
228     for (int i = 0; i < richText.size(); i++)
229     {
230         QString componentStr = "import QtQuick 2.0\nText { text: \"" + richText.at(i) + "\" }";
231         QDeclarativeComponent textComponent(&engine);
232         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
233         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
234
235         QVERIFY(textObject != 0);
236         QString expected = richText.at(i);
237         QCOMPARE(textObject->text(), expected.replace("\\\"", "\""));
238         QVERIFY(textObject->width() > 0);
239
240         delete textObject;
241     }
242 }
243
244 void tst_qquicktext::width()
245 {
246     // uses Font metrics to find the width for standard and document to find the width for rich
247     {
248         QDeclarativeComponent textComponent(&engine);
249         textComponent.setData("import QtQuick 2.0\nText { text: \"\" }", QUrl::fromLocalFile(""));
250         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
251
252         QVERIFY(textObject != 0);
253         QCOMPARE(textObject->width(), 0.);
254
255         delete textObject;
256     }
257
258     bool requiresUnhintedMetrics = !qmlDisableDistanceField();
259
260     for (int i = 0; i < standard.size(); i++)
261     {
262         QVERIFY(!Qt::mightBeRichText(standard.at(i))); // self-test
263
264         QFont f;
265         qreal metricWidth = 0.0;
266
267         if (requiresUnhintedMetrics) {
268             QString s = standard.at(i);
269             s.replace(QLatin1Char('\n'), QChar::LineSeparator);
270
271             QTextLayout layout(s);
272             layout.setFlags(Qt::TextExpandTabs | Qt::TextShowMnemonic);
273             {
274                 QTextOption option;
275                 option.setUseDesignMetrics(true);
276                 layout.setTextOption(option);
277             }
278
279             layout.beginLayout();
280             forever {
281                 QTextLine line = layout.createLine();
282                 if (!line.isValid())
283                     break;
284             }
285
286             layout.endLayout();
287
288             metricWidth = qCeil(layout.boundingRect().width());
289         } else {
290             QFontMetricsF fm(f);
291             qreal metricWidth = fm.size(Qt::TextExpandTabs && Qt::TextShowMnemonic, standard.at(i)).width();
292             metricWidth = qCeil(metricWidth);
293         }
294
295         QString componentStr = "import QtQuick 2.0\nText { text: \"" + standard.at(i) + "\" }";
296         QDeclarativeComponent textComponent(&engine);
297         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
298         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
299
300         QVERIFY(textObject != 0);
301         QVERIFY(textObject->boundingRect().width() > 0);
302         QCOMPARE(textObject->width(), qreal(metricWidth));
303         QVERIFY(textObject->textFormat() == QQuickText::AutoText); // setting text doesn't change format
304
305         delete textObject;
306     }
307
308     for (int i = 0; i < richText.size(); i++)
309     {
310         QVERIFY(Qt::mightBeRichText(richText.at(i))); // self-test
311
312         QString componentStr = "import QtQuick 2.0\nText { text: \"" + richText.at(i) + "\"; textFormat: Text.RichText }";
313         QDeclarativeComponent textComponent(&engine);
314         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
315         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
316         QVERIFY(textObject != 0);
317
318         QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject);
319         QVERIFY(textPrivate != 0);
320
321         QTextDocument *doc = textPrivate->textDocument();
322         QVERIFY(doc != 0);
323
324         QCOMPARE(int(textObject->width()), int(doc->idealWidth()));
325         QVERIFY(textObject->textFormat() == QQuickText::RichText);
326
327         delete textObject;
328     }
329 }
330
331 void tst_qquicktext::wrap()
332 {
333     int textHeight = 0;
334     // for specified width and wrap set true
335     {
336         QDeclarativeComponent textComponent(&engine);
337         textComponent.setData("import QtQuick 2.0\nText { text: \"Hello\"; wrapMode: Text.WordWrap; width: 300 }", QUrl::fromLocalFile(""));
338         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
339         textHeight = textObject->height();
340
341         QVERIFY(textObject != 0);
342         QVERIFY(textObject->wrapMode() == QQuickText::WordWrap);
343         QCOMPARE(textObject->width(), 300.);
344
345         delete textObject;
346     }
347
348     for (int i = 0; i < standard.size(); i++)
349     {
350         QString componentStr = "import QtQuick 2.0\nText { wrapMode: Text.WordWrap; width: 30; text: \"" + standard.at(i) + "\" }";
351         QDeclarativeComponent textComponent(&engine);
352         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
353         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
354
355         QVERIFY(textObject != 0);
356         QCOMPARE(textObject->width(), 30.);
357         QVERIFY(textObject->height() > textHeight);
358
359         int oldHeight = textObject->height();
360         textObject->setWidth(100);
361         QVERIFY(textObject->height() < oldHeight);
362
363         delete textObject;
364     }
365
366     for (int i = 0; i < richText.size(); i++)
367     {
368         QString componentStr = "import QtQuick 2.0\nText { wrapMode: Text.WordWrap; width: 30; text: \"" + richText.at(i) + "\" }";
369         QDeclarativeComponent textComponent(&engine);
370         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
371         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
372
373         QVERIFY(textObject != 0);
374         QCOMPARE(textObject->width(), 30.);
375         QVERIFY(textObject->height() > textHeight);
376
377         qreal oldHeight = textObject->height();
378         textObject->setWidth(100);
379         QVERIFY(textObject->height() < oldHeight);
380
381         delete textObject;
382     }
383
384     // richtext again with a fixed height
385     for (int i = 0; i < richText.size(); i++)
386     {
387         QString componentStr = "import QtQuick 2.0\nText { wrapMode: Text.WordWrap; width: 30; height: 50; text: \"" + richText.at(i) + "\" }";
388         QDeclarativeComponent textComponent(&engine);
389         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
390         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
391
392         QVERIFY(textObject != 0);
393         QCOMPARE(textObject->width(), 30.);
394         QVERIFY(textObject->implicitHeight() > textHeight);
395
396         qreal oldHeight = textObject->implicitHeight();
397         textObject->setWidth(100);
398         QVERIFY(textObject->implicitHeight() < oldHeight);
399
400         delete textObject;
401     }
402 }
403
404 void tst_qquicktext::elide()
405 {
406     for (QQuickText::TextElideMode m = QQuickText::ElideLeft; m<=QQuickText::ElideNone; m=QQuickText::TextElideMode(int(m)+1)) {
407         const char* elidename[]={"ElideLeft", "ElideRight", "ElideMiddle", "ElideNone"};
408         QString elide = "elide: Text." + QString(elidename[int(m)]) + ";";
409
410         // XXX Poor coverage.
411
412         {
413             QDeclarativeComponent textComponent(&engine);
414             textComponent.setData(("import QtQuick 2.0\nText { text: \"\"; "+elide+" width: 100 }").toLatin1(), QUrl::fromLocalFile(""));
415             QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
416
417             QCOMPARE(textObject->elideMode(), m);
418             QCOMPARE(textObject->width(), 100.);
419
420             delete textObject;
421         }
422
423         for (int i = 0; i < standard.size(); i++)
424         {
425             QString componentStr = "import QtQuick 2.0\nText { "+elide+" width: 100; text: \"" + standard.at(i) + "\" }";
426             QDeclarativeComponent textComponent(&engine);
427             textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
428             QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
429
430             QCOMPARE(textObject->elideMode(), m);
431             QCOMPARE(textObject->width(), 100.);
432
433             delete textObject;
434         }
435
436         // richtext - does nothing
437         for (int i = 0; i < richText.size(); i++)
438         {
439             QString componentStr = "import QtQuick 2.0\nText { "+elide+" width: 100; text: \"" + richText.at(i) + "\" }";
440             QDeclarativeComponent textComponent(&engine);
441             textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
442             QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
443
444             QCOMPARE(textObject->elideMode(), m);
445             QCOMPARE(textObject->width(), 100.);
446
447             delete textObject;
448         }
449     }
450 }
451
452 void tst_qquicktext::multilineElide()
453 {
454     QQuickView *canvas = createView(TESTDATA("multilineelide.qml"));
455
456     QQuickText *myText = qobject_cast<QQuickText*>(canvas->rootObject());
457     QVERIFY(myText != 0);
458
459     QCOMPARE(myText->lineCount(), 3);
460     QCOMPARE(myText->truncated(), true);
461
462     qreal lineHeight = myText->paintedHeight() / 3.;
463
464     // reduce size and ensure fewer lines are drawn
465     myText->setHeight(lineHeight * 2);
466     QCOMPARE(myText->lineCount(), 2);
467
468     myText->setHeight(lineHeight);
469     QCOMPARE(myText->lineCount(), 1);
470
471     myText->setHeight(5);
472     QCOMPARE(myText->lineCount(), 1);
473
474     myText->setHeight(lineHeight * 3);
475     QCOMPARE(myText->lineCount(), 3);
476
477     // remove max count and show all lines.
478     myText->setHeight(1000);
479     myText->resetMaximumLineCount();
480
481     QCOMPARE(myText->truncated(), false);
482
483     // reduce size again
484     myText->setHeight(lineHeight * 2);
485     QCOMPARE(myText->lineCount(), 2);
486     QCOMPARE(myText->truncated(), true);
487
488     // change line height
489     myText->setLineHeight(1.1);
490     QCOMPARE(myText->lineCount(), 1);
491
492     delete canvas;
493 }
494
495 void tst_qquicktext::textFormat()
496 {
497     {
498         QDeclarativeComponent textComponent(&engine);
499         textComponent.setData("import QtQuick 2.0\nText { text: \"Hello\"; textFormat: Text.RichText }", QUrl::fromLocalFile(""));
500         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
501
502         QVERIFY(textObject != 0);
503         QVERIFY(textObject->textFormat() == QQuickText::RichText);
504
505         QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject);
506         QVERIFY(textPrivate != 0);
507         QVERIFY(textPrivate->richText == true);
508
509         delete textObject;
510     }
511     {
512         QDeclarativeComponent textComponent(&engine);
513         textComponent.setData("import QtQuick 2.0\nText { text: \"<b>Hello</b>\" }", QUrl::fromLocalFile(""));
514         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
515
516         QVERIFY(textObject != 0);
517         QVERIFY(textObject->textFormat() == QQuickText::AutoText);
518
519         QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject);
520         QVERIFY(textPrivate != 0);
521         QVERIFY(textPrivate->styledText == true);
522
523         delete textObject;
524     }
525     {
526         QDeclarativeComponent textComponent(&engine);
527         textComponent.setData("import QtQuick 2.0\nText { text: \"<b>Hello</b>\"; textFormat: Text.PlainText }", QUrl::fromLocalFile(""));
528         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
529
530         QVERIFY(textObject != 0);
531         QVERIFY(textObject->textFormat() == QQuickText::PlainText);
532
533         delete textObject;
534     }
535 }
536
537
538 void tst_qquicktext::alignments_data()
539 {
540     QTest::addColumn<int>("hAlign");
541     QTest::addColumn<int>("vAlign");
542     QTest::addColumn<QString>("expectfile");
543
544     QTest::newRow("LT") << int(Qt::AlignLeft) << int(Qt::AlignTop) << TESTDATA("alignments_lt.png");
545     QTest::newRow("RT") << int(Qt::AlignRight) << int(Qt::AlignTop) << TESTDATA("alignments_rt.png");
546     QTest::newRow("CT") << int(Qt::AlignHCenter) << int(Qt::AlignTop) << TESTDATA("alignments_ct.png");
547
548     QTest::newRow("LB") << int(Qt::AlignLeft) << int(Qt::AlignBottom) << TESTDATA("alignments_lb.png");
549     QTest::newRow("RB") << int(Qt::AlignRight) << int(Qt::AlignBottom) << TESTDATA("alignments_rb.png");
550     QTest::newRow("CB") << int(Qt::AlignHCenter) << int(Qt::AlignBottom) << TESTDATA("alignments_cb.png");
551
552     QTest::newRow("LC") << int(Qt::AlignLeft) << int(Qt::AlignVCenter) << TESTDATA("alignments_lc.png");
553     QTest::newRow("RC") << int(Qt::AlignRight) << int(Qt::AlignVCenter) << TESTDATA("alignments_rc.png");
554     QTest::newRow("CC") << int(Qt::AlignHCenter) << int(Qt::AlignVCenter) << TESTDATA("alignments_cc.png");
555 }
556
557
558 void tst_qquicktext::alignments()
559 {
560     QSKIP("Text alignment pixmap comparison tests will not work with scenegraph");
561 #if (0)// No widgets in scenegraph
562     QFETCH(int, hAlign);
563     QFETCH(int, vAlign);
564     QFETCH(QString, expectfile);
565
566     QQuickView *canvas = createView(TESTDATA("alignments.qml"));
567     canvas->show();
568     canvas->requestActivateWindow();
569     QTest::qWait(50);
570     QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(canvas));
571
572     QObject *ob = canvas->rootObject();
573     QVERIFY(ob != 0);
574     ob->setProperty("horizontalAlignment",hAlign);
575     ob->setProperty("verticalAlignment",vAlign);
576     QTRY_COMPARE(ob->property("running").toBool(),false);
577     QImage actual(canvas->width(), canvas->height(), QImage::Format_RGB32);
578     actual.fill(qRgb(255,255,255));
579     QPainter p(&actual);
580     canvas->render(&p);
581
582     QImage expect(expectfile);
583     if (QApplicationPrivate::graphics_system_name == "raster" || QApplicationPrivate::graphics_system_name == "") {
584         QCOMPARE(actual,expect);
585     }
586     delete canvas;
587 #endif
588 }
589
590 //the alignment tests may be trivial o.oa
591 void tst_qquicktext::horizontalAlignment()
592 {
593     //test one align each, and then test if two align fails.
594
595     for (int i = 0; i < standard.size(); i++)
596     {
597         for (int j=0; j < horizontalAlignmentmentStrings.size(); j++)
598         {
599             QString componentStr = "import QtQuick 2.0\nText { horizontalAlignment: \"" + horizontalAlignmentmentStrings.at(j) + "\"; text: \"" + standard.at(i) + "\" }";
600             QDeclarativeComponent textComponent(&engine);
601             textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
602             QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
603
604             QCOMPARE((int)textObject->hAlign(), (int)horizontalAlignmentments.at(j));
605
606             delete textObject;
607         }
608     }
609
610     for (int i = 0; i < richText.size(); i++)
611     {
612         for (int j=0; j < horizontalAlignmentmentStrings.size(); j++)
613         {
614             QString componentStr = "import QtQuick 2.0\nText { horizontalAlignment: \"" + horizontalAlignmentmentStrings.at(j) + "\"; text: \"" + richText.at(i) + "\" }";
615             QDeclarativeComponent textComponent(&engine);
616             textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
617             QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
618
619             QCOMPARE((int)textObject->hAlign(), (int)horizontalAlignmentments.at(j));
620
621             delete textObject;
622         }
623     }
624
625 }
626
627 void tst_qquicktext::horizontalAlignment_RightToLeft()
628 {
629     QQuickView *canvas = createView(TESTDATA("horizontalAlignment_RightToLeft.qml"));
630     QQuickText *text = canvas->rootObject()->findChild<QQuickText*>("text");
631     QVERIFY(text != 0);
632     canvas->show();
633
634     QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(text);
635     QVERIFY(textPrivate != 0);
636
637     QTRY_VERIFY(textPrivate->layout.lineCount());
638
639     // implicit alignment should follow the reading direction of RTL text
640     QCOMPARE(text->hAlign(), QQuickText::AlignRight);
641     QCOMPARE(text->effectiveHAlign(), text->hAlign());
642     QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > canvas->width()/2);
643
644     // explicitly left aligned text
645     text->setHAlign(QQuickText::AlignLeft);
646     QCOMPARE(text->hAlign(), QQuickText::AlignLeft);
647     QCOMPARE(text->effectiveHAlign(), text->hAlign());
648     QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() < canvas->width()/2);
649
650     // explicitly right aligned text
651     text->setHAlign(QQuickText::AlignRight);
652     QCOMPARE(text->hAlign(), QQuickText::AlignRight);
653     QCOMPARE(text->effectiveHAlign(), text->hAlign());
654     QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > canvas->width()/2);
655
656     // change to rich text
657     QString textString = text->text();
658     text->setText(QString("<i>") + textString + QString("</i>"));
659     text->setTextFormat(QQuickText::RichText);
660     text->resetHAlign();
661
662     // implicitly aligned rich text should follow the reading direction of text
663     QCOMPARE(text->hAlign(), QQuickText::AlignRight);
664     QCOMPARE(text->effectiveHAlign(), text->hAlign());
665     QVERIFY(textPrivate->textDocument()->defaultTextOption().alignment() & Qt::AlignLeft);
666
667     // explicitly left aligned rich text
668     text->setHAlign(QQuickText::AlignLeft);
669     QCOMPARE(text->hAlign(), QQuickText::AlignLeft);
670     QCOMPARE(text->effectiveHAlign(), text->hAlign());
671     QVERIFY(textPrivate->textDocument()->defaultTextOption().alignment() & Qt::AlignRight);
672
673     // explicitly right aligned rich text
674     text->setHAlign(QQuickText::AlignRight);
675     QCOMPARE(text->hAlign(), QQuickText::AlignRight);
676     QCOMPARE(text->effectiveHAlign(), text->hAlign());
677     QVERIFY(textPrivate->textDocument()->defaultTextOption().alignment() & Qt::AlignLeft);
678
679     text->setText(textString);
680     text->setTextFormat(QQuickText::PlainText);
681
682     // explicitly center aligned
683     text->setHAlign(QQuickText::AlignHCenter);
684     QCOMPARE(text->hAlign(), QQuickText::AlignHCenter);
685     QCOMPARE(text->effectiveHAlign(), text->hAlign());
686     QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() < canvas->width()/2);
687     QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().right() > canvas->width()/2);
688
689     // reseted alignment should go back to following the text reading direction
690     text->resetHAlign();
691     QCOMPARE(text->hAlign(), QQuickText::AlignRight);
692     QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > canvas->width()/2);
693
694     // mirror the text item
695     QQuickItemPrivate::get(text)->setLayoutMirror(true);
696
697     // mirrored implicit alignment should continue to follow the reading direction of the text
698     QCOMPARE(text->hAlign(), QQuickText::AlignRight);
699     QCOMPARE(text->effectiveHAlign(), QQuickText::AlignRight);
700     QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > canvas->width()/2);
701
702     // mirrored explicitly right aligned behaves as left aligned
703     text->setHAlign(QQuickText::AlignRight);
704     QCOMPARE(text->hAlign(), QQuickText::AlignRight);
705     QCOMPARE(text->effectiveHAlign(), QQuickText::AlignLeft);
706     QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() < canvas->width()/2);
707
708     // mirrored explicitly left aligned behaves as right aligned
709     text->setHAlign(QQuickText::AlignLeft);
710     QCOMPARE(text->hAlign(), QQuickText::AlignLeft);
711     QCOMPARE(text->effectiveHAlign(), QQuickText::AlignRight);
712     QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > canvas->width()/2);
713
714     // disable mirroring
715     QQuickItemPrivate::get(text)->setLayoutMirror(false);
716     text->resetHAlign();
717
718     // English text should be implicitly left aligned
719     text->setText("Hello world!");
720     QCOMPARE(text->hAlign(), QQuickText::AlignLeft);
721     QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() < canvas->width()/2);
722
723 #ifndef Q_OS_MAC    // QTBUG-18040
724     // empty text with implicit alignment follows the system locale-based
725     // keyboard input direction from QApplication::keyboardInputDirection
726     text->setText("");
727     QCOMPARE(text->hAlign(), QApplication::keyboardInputDirection() == Qt::LeftToRight ?
728                                   QQuickText::AlignLeft : QQuickText::AlignRight);
729     text->setHAlign(QQuickText::AlignRight);
730     QCOMPARE(text->hAlign(), QQuickText::AlignRight);
731 #endif
732
733     delete canvas;
734
735 #ifndef Q_OS_MAC    // QTBUG-18040
736     // alignment of Text with no text set to it
737     QString componentStr = "import QtQuick 2.0\nText {}";
738     QDeclarativeComponent textComponent(&engine);
739     textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
740     QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
741     QCOMPARE(textObject->hAlign(), QApplication::keyboardInputDirection() == Qt::LeftToRight ?
742                                   QQuickText::AlignLeft : QQuickText::AlignRight);
743     delete textObject;
744 #endif
745 }
746
747 void tst_qquicktext::verticalAlignment()
748 {
749     //test one align each, and then test if two align fails.
750
751     for (int i = 0; i < standard.size(); i++)
752     {
753         for (int j=0; j < verticalAlignmentmentStrings.size(); j++)
754         {
755             QString componentStr = "import QtQuick 2.0\nText { verticalAlignment: \"" + verticalAlignmentmentStrings.at(j) + "\"; text: \"" + standard.at(i) + "\" }";
756             QDeclarativeComponent textComponent(&engine);
757             textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
758             QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
759
760             QVERIFY(textObject != 0);
761             QCOMPARE((int)textObject->vAlign(), (int)verticalAlignmentments.at(j));
762
763             delete textObject;
764         }
765     }
766
767     for (int i = 0; i < richText.size(); i++)
768     {
769         for (int j=0; j < verticalAlignmentmentStrings.size(); j++)
770         {
771             QString componentStr = "import QtQuick 2.0\nText { verticalAlignment: \"" + verticalAlignmentmentStrings.at(j) + "\"; text: \"" + richText.at(i) + "\" }";
772             QDeclarativeComponent textComponent(&engine);
773             textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
774             QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
775
776             QVERIFY(textObject != 0);
777             QCOMPARE((int)textObject->vAlign(), (int)verticalAlignmentments.at(j));
778
779             delete textObject;
780         }
781     }
782
783 }
784
785 void tst_qquicktext::font()
786 {
787     //test size, then bold, then italic, then family
788     {
789         QString componentStr = "import QtQuick 2.0\nText { font.pointSize: 40; text: \"Hello World\" }";
790         QDeclarativeComponent textComponent(&engine);
791         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
792         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
793
794         QCOMPARE(textObject->font().pointSize(), 40);
795         QCOMPARE(textObject->font().bold(), false);
796         QCOMPARE(textObject->font().italic(), false);
797
798         delete textObject;
799     }
800
801     {
802         QString componentStr = "import QtQuick 2.0\nText { font.pixelSize: 40; text: \"Hello World\" }";
803         QDeclarativeComponent textComponent(&engine);
804         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
805         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
806
807         QCOMPARE(textObject->font().pixelSize(), 40);
808         QCOMPARE(textObject->font().bold(), false);
809         QCOMPARE(textObject->font().italic(), false);
810
811         delete textObject;
812     }
813
814     {
815         QString componentStr = "import QtQuick 2.0\nText { font.bold: true; text: \"Hello World\" }";
816         QDeclarativeComponent textComponent(&engine);
817         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
818         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
819
820         QCOMPARE(textObject->font().bold(), true);
821         QCOMPARE(textObject->font().italic(), false);
822
823         delete textObject;
824     }
825
826     {
827         QString componentStr = "import QtQuick 2.0\nText { font.italic: true; text: \"Hello World\" }";
828         QDeclarativeComponent textComponent(&engine);
829         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
830         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
831
832         QCOMPARE(textObject->font().italic(), true);
833         QCOMPARE(textObject->font().bold(), false);
834
835         delete textObject;
836     }
837
838     {
839         QString componentStr = "import QtQuick 2.0\nText { font.family: \"Helvetica\"; text: \"Hello World\" }";
840         QDeclarativeComponent textComponent(&engine);
841         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
842         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
843
844         QCOMPARE(textObject->font().family(), QString("Helvetica"));
845         QCOMPARE(textObject->font().bold(), false);
846         QCOMPARE(textObject->font().italic(), false);
847
848         delete textObject;
849     }
850
851     {
852         QString componentStr = "import QtQuick 2.0\nText { font.family: \"\"; text: \"Hello World\" }";
853         QDeclarativeComponent textComponent(&engine);
854         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
855         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
856
857         QCOMPARE(textObject->font().family(), QString(""));
858
859         delete textObject;
860     }
861 }
862
863 void tst_qquicktext::style()
864 {
865     //test style
866     for (int i = 0; i < styles.size(); i++)
867     {
868         QString componentStr = "import QtQuick 2.0\nText { style: \"" + styleStrings.at(i) + "\"; styleColor: \"white\"; text: \"Hello World\" }";
869         QDeclarativeComponent textComponent(&engine);
870         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
871         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
872
873         QCOMPARE((int)textObject->style(), (int)styles.at(i));
874         QCOMPARE(textObject->styleColor(), QColor("white"));
875
876         delete textObject;
877     }
878     QString componentStr = "import QtQuick 2.0\nText { text: \"Hello World\" }";
879     QDeclarativeComponent textComponent(&engine);
880     textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
881     QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
882
883     QRectF brPre = textObject->boundingRect();
884     textObject->setStyle(QQuickText::Outline);
885     QRectF brPost = textObject->boundingRect();
886
887     QVERIFY(brPre.width() < brPost.width());
888     QVERIFY(brPre.height() < brPost.height());
889
890     delete textObject;
891 }
892
893 void tst_qquicktext::color()
894 {
895     //test style
896     for (int i = 0; i < colorStrings.size(); i++)
897     {
898         QString componentStr = "import QtQuick 2.0\nText { color: \"" + colorStrings.at(i) + "\"; text: \"Hello World\" }";
899         QDeclarativeComponent textComponent(&engine);
900         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
901         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
902
903         QCOMPARE(textObject->color(), QColor(colorStrings.at(i)));
904         QCOMPARE(textObject->styleColor(), QColor());
905
906         delete textObject;
907     }
908
909     for (int i = 0; i < colorStrings.size(); i++)
910     {
911         QString componentStr = "import QtQuick 2.0\nText { styleColor: \"" + colorStrings.at(i) + "\"; text: \"Hello World\" }";
912         QDeclarativeComponent textComponent(&engine);
913         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
914         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
915
916         QCOMPARE(textObject->styleColor(), QColor(colorStrings.at(i)));
917         // default color to black?
918         QCOMPARE(textObject->color(), QColor("black"));
919
920         delete textObject;
921     }
922
923     for (int i = 0; i < colorStrings.size(); i++)
924     {
925         for (int j = 0; j < colorStrings.size(); j++)
926         {
927             QString componentStr = "import QtQuick 2.0\nText { color: \"" + colorStrings.at(i) + "\"; styleColor: \"" + colorStrings.at(j) + "\"; text: \"Hello World\" }";
928             QDeclarativeComponent textComponent(&engine);
929             textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
930             QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
931
932             QCOMPARE(textObject->color(), QColor(colorStrings.at(i)));
933             QCOMPARE(textObject->styleColor(), QColor(colorStrings.at(j)));
934
935             delete textObject;
936         }
937     }
938     {
939         QString colorStr = "#AA001234";
940         QColor testColor("#001234");
941         testColor.setAlpha(170);
942
943         QString componentStr = "import QtQuick 2.0\nText { color: \"" + colorStr + "\"; text: \"Hello World\" }";
944         QDeclarativeComponent textComponent(&engine);
945         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
946         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
947
948         QCOMPARE(textObject->color(), testColor);
949
950         delete textObject;
951     }
952 }
953
954 void tst_qquicktext::smooth()
955 {
956     for (int i = 0; i < standard.size(); i++)
957     {
958         {
959             QString componentStr = "import QtQuick 2.0\nText { smooth: true; text: \"" + standard.at(i) + "\" }";
960             QDeclarativeComponent textComponent(&engine);
961             textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
962             QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
963             QCOMPARE(textObject->smooth(), true);
964
965             delete textObject;
966         }
967         {
968             QString componentStr = "import QtQuick 2.0\nText { text: \"" + standard.at(i) + "\" }";
969             QDeclarativeComponent textComponent(&engine);
970             textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
971             QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
972             QCOMPARE(textObject->smooth(), false);
973
974             delete textObject;
975         }
976     }
977     for (int i = 0; i < richText.size(); i++)
978     {
979         {
980             QString componentStr = "import QtQuick 2.0\nText { smooth: true; text: \"" + richText.at(i) + "\" }";
981             QDeclarativeComponent textComponent(&engine);
982             textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
983             QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
984             QCOMPARE(textObject->smooth(), true);
985
986             delete textObject;
987         }
988         {
989             QString componentStr = "import QtQuick 2.0\nText { text: \"" + richText.at(i) + "\" }";
990             QDeclarativeComponent textComponent(&engine);
991             textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
992             QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
993             QCOMPARE(textObject->smooth(), false);
994
995             delete textObject;
996         }
997     }
998 }
999
1000 void tst_qquicktext::weight()
1001 {
1002     {
1003         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
1004         QDeclarativeComponent textComponent(&engine);
1005         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1006         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1007
1008         QVERIFY(textObject != 0);
1009         QCOMPARE((int)textObject->font().weight(), (int)QDeclarativeFontValueType::Normal);
1010
1011         delete textObject;
1012     }
1013     {
1014         QString componentStr = "import QtQuick 2.0\nText { font.weight: \"Bold\"; text: \"Hello world!\" }";
1015         QDeclarativeComponent textComponent(&engine);
1016         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1017         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1018
1019         QVERIFY(textObject != 0);
1020         QCOMPARE((int)textObject->font().weight(), (int)QDeclarativeFontValueType::Bold);
1021
1022         delete textObject;
1023     }
1024 }
1025
1026 void tst_qquicktext::underline()
1027 {
1028     {
1029         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
1030         QDeclarativeComponent textComponent(&engine);
1031         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1032         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1033
1034         QVERIFY(textObject != 0);
1035         QCOMPARE(textObject->font().underline(), false);
1036
1037         delete textObject;
1038     }
1039     {
1040         QString componentStr = "import QtQuick 2.0\nText { font.underline: true; text: \"Hello world!\" }";
1041         QDeclarativeComponent textComponent(&engine);
1042         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1043         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1044
1045         QVERIFY(textObject != 0);
1046         QCOMPARE(textObject->font().underline(), true);
1047
1048         delete textObject;
1049     }
1050 }
1051
1052 void tst_qquicktext::overline()
1053 {
1054     {
1055         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
1056         QDeclarativeComponent textComponent(&engine);
1057         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1058         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1059
1060         QVERIFY(textObject != 0);
1061         QCOMPARE(textObject->font().overline(), false);
1062
1063         delete textObject;
1064     }
1065     {
1066         QString componentStr = "import QtQuick 2.0\nText { font.overline: true; text: \"Hello world!\" }";
1067         QDeclarativeComponent textComponent(&engine);
1068         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1069         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1070
1071         QVERIFY(textObject != 0);
1072         QCOMPARE(textObject->font().overline(), true);
1073
1074         delete textObject;
1075     }
1076 }
1077
1078 void tst_qquicktext::strikeout()
1079 {
1080     {
1081         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
1082         QDeclarativeComponent textComponent(&engine);
1083         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1084         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1085
1086         QVERIFY(textObject != 0);
1087         QCOMPARE(textObject->font().strikeOut(), false);
1088
1089         delete textObject;
1090     }
1091     {
1092         QString componentStr = "import QtQuick 2.0\nText { font.strikeout: true; text: \"Hello world!\" }";
1093         QDeclarativeComponent textComponent(&engine);
1094         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1095         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1096
1097         QVERIFY(textObject != 0);
1098         QCOMPARE(textObject->font().strikeOut(), true);
1099
1100         delete textObject;
1101     }
1102 }
1103
1104 void tst_qquicktext::capitalization()
1105 {
1106     {
1107         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
1108         QDeclarativeComponent textComponent(&engine);
1109         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1110         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1111
1112         QVERIFY(textObject != 0);
1113         QCOMPARE((int)textObject->font().capitalization(), (int)QDeclarativeFontValueType::MixedCase);
1114
1115         delete textObject;
1116     }
1117     {
1118         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.capitalization: \"AllUppercase\" }";
1119         QDeclarativeComponent textComponent(&engine);
1120         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1121         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1122
1123         QVERIFY(textObject != 0);
1124         QCOMPARE((int)textObject->font().capitalization(), (int)QDeclarativeFontValueType::AllUppercase);
1125
1126         delete textObject;
1127     }
1128     {
1129         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.capitalization: \"AllLowercase\" }";
1130         QDeclarativeComponent textComponent(&engine);
1131         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1132         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1133
1134         QVERIFY(textObject != 0);
1135         QCOMPARE((int)textObject->font().capitalization(), (int)QDeclarativeFontValueType::AllLowercase);
1136
1137         delete textObject;
1138     }
1139     {
1140         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.capitalization: \"SmallCaps\" }";
1141         QDeclarativeComponent textComponent(&engine);
1142         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1143         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1144
1145         QVERIFY(textObject != 0);
1146         QCOMPARE((int)textObject->font().capitalization(), (int)QDeclarativeFontValueType::SmallCaps);
1147
1148         delete textObject;
1149     }
1150     {
1151         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.capitalization: \"Capitalize\" }";
1152         QDeclarativeComponent textComponent(&engine);
1153         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1154         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1155
1156         QVERIFY(textObject != 0);
1157         QCOMPARE((int)textObject->font().capitalization(), (int)QDeclarativeFontValueType::Capitalize);
1158
1159         delete textObject;
1160     }
1161 }
1162
1163 void tst_qquicktext::letterSpacing()
1164 {
1165     {
1166         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
1167         QDeclarativeComponent textComponent(&engine);
1168         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1169         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1170
1171         QVERIFY(textObject != 0);
1172         QCOMPARE(textObject->font().letterSpacing(), 0.0);
1173
1174         delete textObject;
1175     }
1176     {
1177         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.letterSpacing: -2 }";
1178         QDeclarativeComponent textComponent(&engine);
1179         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1180         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1181
1182         QVERIFY(textObject != 0);
1183         QCOMPARE(textObject->font().letterSpacing(), -2.);
1184
1185         delete textObject;
1186     }
1187     {
1188         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.letterSpacing: 3 }";
1189         QDeclarativeComponent textComponent(&engine);
1190         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1191         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1192
1193         QVERIFY(textObject != 0);
1194         QCOMPARE(textObject->font().letterSpacing(), 3.);
1195
1196         delete textObject;
1197     }
1198 }
1199
1200 void tst_qquicktext::wordSpacing()
1201 {
1202     {
1203         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
1204         QDeclarativeComponent textComponent(&engine);
1205         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1206         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1207
1208         QVERIFY(textObject != 0);
1209         QCOMPARE(textObject->font().wordSpacing(), 0.0);
1210
1211         delete textObject;
1212     }
1213     {
1214         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.wordSpacing: -50 }";
1215         QDeclarativeComponent textComponent(&engine);
1216         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1217         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1218
1219         QVERIFY(textObject != 0);
1220         QCOMPARE(textObject->font().wordSpacing(), -50.);
1221
1222         delete textObject;
1223     }
1224     {
1225         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.wordSpacing: 200 }";
1226         QDeclarativeComponent textComponent(&engine);
1227         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1228         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1229
1230         QVERIFY(textObject != 0);
1231         QCOMPARE(textObject->font().wordSpacing(), 200.);
1232
1233         delete textObject;
1234     }
1235 }
1236
1237
1238
1239
1240 class EventSender : public QQuickItem
1241 {
1242 public:
1243     void sendEvent(QMouseEvent *event) {
1244         if (event->type() == QEvent::MouseButtonPress)
1245             mousePressEvent(event);
1246         else if (event->type() == QEvent::MouseButtonRelease)
1247             mouseReleaseEvent(event);
1248         else
1249             qWarning() << "Trying to send unsupported event type";
1250     }
1251 };
1252
1253 class LinkTest : public QObject
1254 {
1255     Q_OBJECT
1256 public:
1257     LinkTest() {}
1258
1259     QString link;
1260
1261 public slots:
1262     void linkClicked(QString l) { link = l; }
1263 };
1264
1265 void tst_qquicktext::clickLink()
1266 {
1267     {
1268         QString componentStr = "import QtQuick 2.0\nText { text: \"<a href=\\\"http://qt.nokia.com\\\">Hello world!</a>\" }";
1269         QDeclarativeComponent textComponent(&engine);
1270         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1271         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1272
1273         QVERIFY(textObject != 0);
1274
1275         LinkTest test;
1276         QObject::connect(textObject, SIGNAL(linkActivated(QString)), &test, SLOT(linkClicked(QString)));
1277
1278         {
1279             QMouseEvent me(QEvent::MouseButtonPress,QPointF(textObject->x()/2, textObject->y()/2), Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
1280             static_cast<EventSender*>(static_cast<QQuickItem*>(textObject))->sendEvent(&me);
1281
1282         }
1283
1284         {
1285             QMouseEvent me(QEvent::MouseButtonRelease,QPointF(textObject->x()/2, textObject->y()/2), Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
1286             static_cast<EventSender*>(static_cast<QQuickItem*>(textObject))->sendEvent(&me);
1287
1288         }
1289
1290
1291         QCOMPARE(test.link, QLatin1String("http://qt.nokia.com"));
1292
1293         delete textObject;
1294     }
1295 }
1296
1297 void tst_qquicktext::embeddedImages_data()
1298 {
1299     QTest::addColumn<QUrl>("qmlfile");
1300     QTest::addColumn<QString>("error");
1301     QTest::newRow("local") << QUrl::fromLocalFile(TESTDATA("embeddedImagesLocal.qml")) << "";
1302     QTest::newRow("local-error") << QUrl::fromLocalFile(TESTDATA("embeddedImagesLocalError.qml"))
1303         << QUrl::fromLocalFile(TESTDATA("embeddedImagesLocalError.qml")).toString()+":3:1: QML Text: Cannot open: " + QUrl::fromLocalFile(TESTDATA("http/notexists.png")).toString();
1304     QTest::newRow("remote") << QUrl::fromLocalFile(TESTDATA("embeddedImagesRemote.qml")) << "";
1305     QTest::newRow("remote-error") << QUrl::fromLocalFile(TESTDATA("embeddedImagesRemoteError.qml"))
1306         << QUrl::fromLocalFile(TESTDATA("embeddedImagesRemoteError.qml")).toString()+":3:1: QML Text: Error downloading http://127.0.0.1:14453/notexists.png - server replied: Not found";
1307 }
1308
1309 void tst_qquicktext::embeddedImages()
1310 {
1311     // Tests QTBUG-9900
1312
1313     QFETCH(QUrl, qmlfile);
1314     QFETCH(QString, error);
1315
1316     TestHTTPServer server(14453);
1317     server.serveDirectory(TESTDATA("http"));
1318
1319     if (!error.isEmpty())
1320         QTest::ignoreMessage(QtWarningMsg, error.toLatin1());
1321
1322     QDeclarativeComponent textComponent(&engine, qmlfile);
1323     QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1324
1325     QVERIFY(textObject != 0);
1326
1327     QTRY_COMPARE(textObject->resourcesLoading(), 0);
1328
1329     QPixmap pm(TESTDATA("http/exists.png"));
1330     if (error.isEmpty()) {
1331         QCOMPARE(textObject->width(), double(pm.width()));
1332         QCOMPARE(textObject->height(), double(pm.height()));
1333     } else {
1334         QVERIFY(16 != pm.width()); // check test is effective
1335         QCOMPARE(textObject->width(), 16.0); // default size of QTextDocument broken image icon
1336         QCOMPARE(textObject->height(), 16.0);
1337     }
1338
1339     delete textObject;
1340 }
1341
1342 void tst_qquicktext::lineCount()
1343 {
1344     QQuickView *canvas = createView(TESTDATA("lineCount.qml"));
1345
1346     QQuickText *myText = canvas->rootObject()->findChild<QQuickText*>("myText");
1347     QVERIFY(myText != 0);
1348
1349     QVERIFY(myText->lineCount() > 1);
1350     QVERIFY(!myText->truncated());
1351     QCOMPARE(myText->maximumLineCount(), INT_MAX);
1352
1353     myText->setMaximumLineCount(2);
1354     QCOMPARE(myText->lineCount(), 2);
1355     QCOMPARE(myText->truncated(), true);
1356     QCOMPARE(myText->maximumLineCount(), 2);
1357
1358     myText->resetMaximumLineCount();
1359     QCOMPARE(myText->maximumLineCount(), INT_MAX);
1360     QCOMPARE(myText->truncated(), false);
1361
1362     myText->setElideMode(QQuickText::ElideRight);
1363     myText->setMaximumLineCount(2);
1364     QCOMPARE(myText->lineCount(), 2);
1365     QCOMPARE(myText->truncated(), true);
1366     QCOMPARE(myText->maximumLineCount(), 2);
1367
1368     delete canvas;
1369 }
1370
1371 void tst_qquicktext::lineHeight()
1372 {
1373     QQuickView *canvas = createView(TESTDATA("lineHeight.qml"));
1374
1375     QQuickText *myText = canvas->rootObject()->findChild<QQuickText*>("myText");
1376     QVERIFY(myText != 0);
1377
1378     QVERIFY(myText->lineHeight() == 1);
1379     QVERIFY(myText->lineHeightMode() == QQuickText::ProportionalHeight);
1380
1381     qreal h = myText->height();
1382     myText->setLineHeight(1.5);
1383     QVERIFY(myText->height() == qCeil(h * 1.5));
1384
1385     myText->setLineHeightMode(QQuickText::FixedHeight);
1386     myText->setLineHeight(20);
1387     QCOMPARE(myText->height(), myText->lineCount() * 20.0);
1388
1389     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.");
1390     myText->setLineHeightMode(QQuickText::ProportionalHeight);
1391     myText->setLineHeight(1.0);
1392
1393     qreal h2 = myText->height();
1394     myText->setLineHeight(2.0);
1395     QVERIFY(myText->height() == h2 * 2.0);
1396
1397     myText->setLineHeightMode(QQuickText::FixedHeight);
1398     myText->setLineHeight(10);
1399     QCOMPARE(myText->height(), myText->lineCount() * 10.0);
1400
1401     delete canvas;
1402 }
1403
1404 void tst_qquicktext::implicitSize_data()
1405 {
1406     QTest::addColumn<QString>("text");
1407     QTest::addColumn<QString>("wrap");
1408     QTest::newRow("plain") << "The quick red fox jumped over the lazy brown dog" << "Text.NoWrap";
1409     QTest::newRow("richtext") << "<b>The quick red fox jumped over the lazy brown dog</b>" << "Text.NoWrap";
1410     QTest::newRow("plain_wrap") << "The quick red fox jumped over the lazy brown dog" << "Text.Wrap";
1411     QTest::newRow("richtext_wrap") << "<b>The quick red fox jumped over the lazy brown dog</b>" << "Text.Wrap";
1412 }
1413
1414 void tst_qquicktext::implicitSize()
1415 {
1416     QFETCH(QString, text);
1417     QFETCH(QString, wrap);
1418     QString componentStr = "import QtQuick 2.0\nText { text: \"" + text + "\"; width: 50; wrapMode: " + wrap + " }";
1419     QDeclarativeComponent textComponent(&engine);
1420     textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1421     QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1422
1423     QVERIFY(textObject->width() < textObject->implicitWidth());
1424     QVERIFY(textObject->height() == textObject->implicitHeight());
1425
1426     textObject->resetWidth();
1427     QVERIFY(textObject->width() == textObject->implicitWidth());
1428     QVERIFY(textObject->height() == textObject->implicitHeight());
1429
1430     delete textObject;
1431 }
1432
1433 void tst_qquicktext::lineLaidOut()
1434 {
1435     QQuickView *canvas = createView(TESTDATA("lineLayout.qml"));
1436
1437     QQuickText *myText = canvas->rootObject()->findChild<QQuickText*>("myText");
1438     QVERIFY(myText != 0);
1439
1440     QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(myText);
1441     QVERIFY(textPrivate != 0);
1442
1443     QTextDocument *doc = textPrivate->textDocument();
1444     QVERIFY(doc == 0);
1445
1446     QVERIFY(myText->lineCount() == textPrivate->linesRects.count());
1447
1448     for (int i = 0; i < textPrivate->linesRects.count(); ++i) {
1449         QRectF r = textPrivate->linesRects.at(i);
1450         QVERIFY(r.width() == i * 15);
1451         if (i >= 30)
1452             QVERIFY(r.x() == r.width() + 30);
1453         if (i >= 60) {
1454             QVERIFY(r.x() == r.width() * 2 + 60);
1455             QVERIFY(r.height() == 20);
1456         }
1457     }
1458
1459     delete canvas;
1460 }
1461
1462 QTEST_MAIN(tst_qquicktext)
1463
1464 #include "tst_qquicktext.moc"