3a08dd208dd2bbe5220d6a574af81630ccd22a8d
[profile/ivi/qtdeclarative.git] / tests / auto / declarative / 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 <private/qquicktext_p.h>
46 #include <private/qquicktext_p_p.h>
47 #include <private/qdeclarativevaluetype_p.h>
48 #include <private/qsgdistancefieldglyphcache_p.h>
49 #include <QFontMetrics>
50 #include <QGraphicsSceneMouseEvent>
51 #include <qmath.h>
52 #include <QQuickView>
53 #include <private/qapplication_p.h>
54 #include <limits.h>
55 #include <QtGui/QMouseEvent>
56 #include "../shared/util.h"
57 #include "testhttpserver.h"
58
59 DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
60
61 class tst_qquicktext : public QObject
62 {
63     Q_OBJECT
64 public:
65     tst_qquicktext();
66
67 private slots:
68     void initTestCase();
69     void cleanupTestCase();
70     void text();
71     void width();
72     void wrap();
73     void elide();
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::textFormat()
453 {
454     {
455         QDeclarativeComponent textComponent(&engine);
456         textComponent.setData("import QtQuick 2.0\nText { text: \"Hello\"; textFormat: Text.RichText }", QUrl::fromLocalFile(""));
457         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
458
459         QVERIFY(textObject != 0);
460         QVERIFY(textObject->textFormat() == QQuickText::RichText);
461
462         QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject);
463         QVERIFY(textPrivate != 0);
464         QVERIFY(textPrivate->richText == true);
465
466         delete textObject;
467     }
468     {
469         QDeclarativeComponent textComponent(&engine);
470         textComponent.setData("import QtQuick 2.0\nText { text: \"<b>Hello</b>\" }", QUrl::fromLocalFile(""));
471         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
472
473         QVERIFY(textObject != 0);
474         QVERIFY(textObject->textFormat() == QQuickText::AutoText);
475
476         QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject);
477         QVERIFY(textPrivate != 0);
478         QVERIFY(textPrivate->styledText == true);
479
480         delete textObject;
481     }
482     {
483         QDeclarativeComponent textComponent(&engine);
484         textComponent.setData("import QtQuick 2.0\nText { text: \"<b>Hello</b>\"; textFormat: Text.PlainText }", QUrl::fromLocalFile(""));
485         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
486
487         QVERIFY(textObject != 0);
488         QVERIFY(textObject->textFormat() == QQuickText::PlainText);
489
490         delete textObject;
491     }
492 }
493
494
495 void tst_qquicktext::alignments_data()
496 {
497     QTest::addColumn<int>("hAlign");
498     QTest::addColumn<int>("vAlign");
499     QTest::addColumn<QString>("expectfile");
500
501     QTest::newRow("LT") << int(Qt::AlignLeft) << int(Qt::AlignTop) << TESTDATA("alignments_lt.png");
502     QTest::newRow("RT") << int(Qt::AlignRight) << int(Qt::AlignTop) << TESTDATA("alignments_rt.png");
503     QTest::newRow("CT") << int(Qt::AlignHCenter) << int(Qt::AlignTop) << TESTDATA("alignments_ct.png");
504
505     QTest::newRow("LB") << int(Qt::AlignLeft) << int(Qt::AlignBottom) << TESTDATA("alignments_lb.png");
506     QTest::newRow("RB") << int(Qt::AlignRight) << int(Qt::AlignBottom) << TESTDATA("alignments_rb.png");
507     QTest::newRow("CB") << int(Qt::AlignHCenter) << int(Qt::AlignBottom) << TESTDATA("alignments_cb.png");
508
509     QTest::newRow("LC") << int(Qt::AlignLeft) << int(Qt::AlignVCenter) << TESTDATA("alignments_lc.png");
510     QTest::newRow("RC") << int(Qt::AlignRight) << int(Qt::AlignVCenter) << TESTDATA("alignments_rc.png");
511     QTest::newRow("CC") << int(Qt::AlignHCenter) << int(Qt::AlignVCenter) << TESTDATA("alignments_cc.png");
512 }
513
514
515 void tst_qquicktext::alignments()
516 {
517     QSKIP("Text alignment pixmap comparison tests will not work with scenegraph");
518 #if (0)// No widgets in scenegraph
519     QFETCH(int, hAlign);
520     QFETCH(int, vAlign);
521     QFETCH(QString, expectfile);
522
523 #ifdef Q_WS_X11
524     // Font-specific, but not likely platform-specific, so only test on one platform
525     QFont fn;
526     fn.setRawName("-misc-fixed-medium-r-*-*-8-*-*-*-*-*-*-*");
527     QApplication::setFont(fn);
528 #endif
529
530     QQuickView *canvas = createView(TESTDATA("alignments.qml"));
531
532     canvas->show();
533     canvas->requestActivateWindow();
534     QTest::qWait(50);
535     QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(canvas));
536
537     QObject *ob = canvas->rootObject();
538     QVERIFY(ob != 0);
539     ob->setProperty("horizontalAlignment",hAlign);
540     ob->setProperty("verticalAlignment",vAlign);
541     QTRY_COMPARE(ob->property("running").toBool(),false);
542     QImage actual(canvas->width(), canvas->height(), QImage::Format_RGB32);
543     actual.fill(qRgb(255,255,255));
544     QPainter p(&actual);
545     canvas->render(&p);
546
547     QImage expect(expectfile);
548
549 #ifdef Q_WS_X11
550     // Font-specific, but not likely platform-specific, so only test on one platform
551     if (QApplicationPrivate::graphics_system_name == "raster" || QApplicationPrivate::graphics_system_name == "") {
552         QCOMPARE(actual,expect);
553     }
554 #endif
555
556     delete canvas;
557 #endif
558 }
559
560 //the alignment tests may be trivial o.oa
561 void tst_qquicktext::horizontalAlignment()
562 {
563     //test one align each, and then test if two align fails.
564
565     for (int i = 0; i < standard.size(); i++)
566     {
567         for (int j=0; j < horizontalAlignmentmentStrings.size(); j++)
568         {
569             QString componentStr = "import QtQuick 2.0\nText { horizontalAlignment: \"" + horizontalAlignmentmentStrings.at(j) + "\"; text: \"" + standard.at(i) + "\" }";
570             QDeclarativeComponent textComponent(&engine);
571             textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
572             QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
573
574             QCOMPARE((int)textObject->hAlign(), (int)horizontalAlignmentments.at(j));
575
576             delete textObject;
577         }
578     }
579
580     for (int i = 0; i < richText.size(); i++)
581     {
582         for (int j=0; j < horizontalAlignmentmentStrings.size(); j++)
583         {
584             QString componentStr = "import QtQuick 2.0\nText { horizontalAlignment: \"" + horizontalAlignmentmentStrings.at(j) + "\"; text: \"" + richText.at(i) + "\" }";
585             QDeclarativeComponent textComponent(&engine);
586             textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
587             QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
588
589             QCOMPARE((int)textObject->hAlign(), (int)horizontalAlignmentments.at(j));
590
591             delete textObject;
592         }
593     }
594
595 }
596
597 void tst_qquicktext::horizontalAlignment_RightToLeft()
598 {
599     QQuickView *canvas = createView(TESTDATA("horizontalAlignment_RightToLeft.qml"));
600     QQuickText *text = canvas->rootObject()->findChild<QQuickText*>("text");
601     QVERIFY(text != 0);
602     canvas->show();
603
604     QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(text);
605     QVERIFY(textPrivate != 0);
606
607     // implicit alignment should follow the reading direction of RTL text
608     QCOMPARE(text->hAlign(), QQuickText::AlignRight);
609     QCOMPARE(text->effectiveHAlign(), text->hAlign());
610     QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > canvas->width()/2);
611
612     // explicitly left aligned text
613     text->setHAlign(QQuickText::AlignLeft);
614     QCOMPARE(text->hAlign(), QQuickText::AlignLeft);
615     QCOMPARE(text->effectiveHAlign(), text->hAlign());
616     QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() < canvas->width()/2);
617
618     // explicitly right aligned text
619     text->setHAlign(QQuickText::AlignRight);
620     QCOMPARE(text->hAlign(), QQuickText::AlignRight);
621     QCOMPARE(text->effectiveHAlign(), text->hAlign());
622     QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > canvas->width()/2);
623
624     // change to rich text
625     QString textString = text->text();
626     text->setText(QString("<i>") + textString + QString("</i>"));
627     text->setTextFormat(QQuickText::RichText);
628     text->resetHAlign();
629
630     // implicitly aligned rich text should follow the reading direction of text
631     QCOMPARE(text->hAlign(), QQuickText::AlignRight);
632     QCOMPARE(text->effectiveHAlign(), text->hAlign());
633     QVERIFY(textPrivate->textDocument()->defaultTextOption().alignment() & Qt::AlignLeft);
634
635     // explicitly left aligned rich text
636     text->setHAlign(QQuickText::AlignLeft);
637     QCOMPARE(text->hAlign(), QQuickText::AlignLeft);
638     QCOMPARE(text->effectiveHAlign(), text->hAlign());
639     QVERIFY(textPrivate->textDocument()->defaultTextOption().alignment() & Qt::AlignRight);
640
641     // explicitly right aligned rich text
642     text->setHAlign(QQuickText::AlignRight);
643     QCOMPARE(text->hAlign(), QQuickText::AlignRight);
644     QCOMPARE(text->effectiveHAlign(), text->hAlign());
645     QVERIFY(textPrivate->textDocument()->defaultTextOption().alignment() & Qt::AlignLeft);
646
647     text->setText(textString);
648     text->setTextFormat(QQuickText::PlainText);
649
650     // explicitly center aligned
651     text->setHAlign(QQuickText::AlignHCenter);
652     QCOMPARE(text->hAlign(), QQuickText::AlignHCenter);
653     QCOMPARE(text->effectiveHAlign(), text->hAlign());
654     QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() < canvas->width()/2);
655     QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().right() > canvas->width()/2);
656
657     // reseted alignment should go back to following the text reading direction
658     text->resetHAlign();
659     QCOMPARE(text->hAlign(), QQuickText::AlignRight);
660     QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > canvas->width()/2);
661
662     // mirror the text item
663     QQuickItemPrivate::get(text)->setLayoutMirror(true);
664
665     // mirrored implicit alignment should continue to follow the reading direction of the text
666     QCOMPARE(text->hAlign(), QQuickText::AlignRight);
667     QCOMPARE(text->effectiveHAlign(), QQuickText::AlignRight);
668     QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > canvas->width()/2);
669
670     // mirrored explicitly right aligned behaves as left aligned
671     text->setHAlign(QQuickText::AlignRight);
672     QCOMPARE(text->hAlign(), QQuickText::AlignRight);
673     QCOMPARE(text->effectiveHAlign(), QQuickText::AlignLeft);
674     QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() < canvas->width()/2);
675
676     // mirrored explicitly left aligned behaves as right aligned
677     text->setHAlign(QQuickText::AlignLeft);
678     QCOMPARE(text->hAlign(), QQuickText::AlignLeft);
679     QCOMPARE(text->effectiveHAlign(), QQuickText::AlignRight);
680     QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > canvas->width()/2);
681
682     // disable mirroring
683     QQuickItemPrivate::get(text)->setLayoutMirror(false);
684     text->resetHAlign();
685
686     // English text should be implicitly left aligned
687     text->setText("Hello world!");
688     QCOMPARE(text->hAlign(), QQuickText::AlignLeft);
689     QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() < canvas->width()/2);
690
691 #ifndef Q_OS_MAC    // QTBUG-18040
692     // empty text with implicit alignment follows the system locale-based
693     // keyboard input direction from QApplication::keyboardInputDirection
694     text->setText("");
695     QCOMPARE(text->hAlign(), QApplication::keyboardInputDirection() == Qt::LeftToRight ?
696                                   QQuickText::AlignLeft : QQuickText::AlignRight);
697     text->setHAlign(QQuickText::AlignRight);
698     QCOMPARE(text->hAlign(), QQuickText::AlignRight);
699 #endif
700
701     delete canvas;
702
703 #ifndef Q_OS_MAC    // QTBUG-18040
704     // alignment of Text with no text set to it
705     QString componentStr = "import QtQuick 2.0\nText {}";
706     QDeclarativeComponent textComponent(&engine);
707     textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
708     QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
709     QCOMPARE(textObject->hAlign(), QApplication::keyboardInputDirection() == Qt::LeftToRight ?
710                                   QQuickText::AlignLeft : QQuickText::AlignRight);
711     delete textObject;
712 #endif
713 }
714
715 void tst_qquicktext::verticalAlignment()
716 {
717     //test one align each, and then test if two align fails.
718
719     for (int i = 0; i < standard.size(); i++)
720     {
721         for (int j=0; j < verticalAlignmentmentStrings.size(); j++)
722         {
723             QString componentStr = "import QtQuick 2.0\nText { verticalAlignment: \"" + verticalAlignmentmentStrings.at(j) + "\"; text: \"" + standard.at(i) + "\" }";
724             QDeclarativeComponent textComponent(&engine);
725             textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
726             QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
727
728             QVERIFY(textObject != 0);
729             QCOMPARE((int)textObject->vAlign(), (int)verticalAlignmentments.at(j));
730
731             delete textObject;
732         }
733     }
734
735     for (int i = 0; i < richText.size(); i++)
736     {
737         for (int j=0; j < verticalAlignmentmentStrings.size(); j++)
738         {
739             QString componentStr = "import QtQuick 2.0\nText { verticalAlignment: \"" + verticalAlignmentmentStrings.at(j) + "\"; text: \"" + richText.at(i) + "\" }";
740             QDeclarativeComponent textComponent(&engine);
741             textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
742             QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
743
744             QVERIFY(textObject != 0);
745             QCOMPARE((int)textObject->vAlign(), (int)verticalAlignmentments.at(j));
746
747             delete textObject;
748         }
749     }
750
751 }
752
753 void tst_qquicktext::font()
754 {
755     //test size, then bold, then italic, then family
756     {
757         QString componentStr = "import QtQuick 2.0\nText { font.pointSize: 40; text: \"Hello World\" }";
758         QDeclarativeComponent textComponent(&engine);
759         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
760         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
761
762         QCOMPARE(textObject->font().pointSize(), 40);
763         QCOMPARE(textObject->font().bold(), false);
764         QCOMPARE(textObject->font().italic(), false);
765
766         delete textObject;
767     }
768
769     {
770         QString componentStr = "import QtQuick 2.0\nText { font.pixelSize: 40; text: \"Hello World\" }";
771         QDeclarativeComponent textComponent(&engine);
772         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
773         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
774
775         QCOMPARE(textObject->font().pixelSize(), 40);
776         QCOMPARE(textObject->font().bold(), false);
777         QCOMPARE(textObject->font().italic(), false);
778
779         delete textObject;
780     }
781
782     {
783         QString componentStr = "import QtQuick 2.0\nText { font.bold: true; text: \"Hello World\" }";
784         QDeclarativeComponent textComponent(&engine);
785         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
786         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
787
788         QCOMPARE(textObject->font().bold(), true);
789         QCOMPARE(textObject->font().italic(), false);
790
791         delete textObject;
792     }
793
794     {
795         QString componentStr = "import QtQuick 2.0\nText { font.italic: true; text: \"Hello World\" }";
796         QDeclarativeComponent textComponent(&engine);
797         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
798         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
799
800         QCOMPARE(textObject->font().italic(), true);
801         QCOMPARE(textObject->font().bold(), false);
802
803         delete textObject;
804     }
805
806     {
807         QString componentStr = "import QtQuick 2.0\nText { font.family: \"Helvetica\"; text: \"Hello World\" }";
808         QDeclarativeComponent textComponent(&engine);
809         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
810         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
811
812         QCOMPARE(textObject->font().family(), QString("Helvetica"));
813         QCOMPARE(textObject->font().bold(), false);
814         QCOMPARE(textObject->font().italic(), false);
815
816         delete textObject;
817     }
818
819     {
820         QString componentStr = "import QtQuick 2.0\nText { font.family: \"\"; text: \"Hello World\" }";
821         QDeclarativeComponent textComponent(&engine);
822         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
823         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
824
825         QCOMPARE(textObject->font().family(), QString(""));
826
827         delete textObject;
828     }
829 }
830
831 void tst_qquicktext::style()
832 {
833     //test style
834     for (int i = 0; i < styles.size(); i++)
835     {
836         QString componentStr = "import QtQuick 2.0\nText { style: \"" + styleStrings.at(i) + "\"; styleColor: \"white\"; text: \"Hello World\" }";
837         QDeclarativeComponent textComponent(&engine);
838         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
839         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
840
841         QCOMPARE((int)textObject->style(), (int)styles.at(i));
842         QCOMPARE(textObject->styleColor(), QColor("white"));
843
844         delete textObject;
845     }
846     QString componentStr = "import QtQuick 2.0\nText { text: \"Hello World\" }";
847     QDeclarativeComponent textComponent(&engine);
848     textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
849     QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
850
851     QRectF brPre = textObject->boundingRect();
852     textObject->setStyle(QQuickText::Outline);
853     QRectF brPost = textObject->boundingRect();
854
855     QVERIFY(brPre.width() < brPost.width());
856     QVERIFY(brPre.height() < brPost.height());
857
858     delete textObject;
859 }
860
861 void tst_qquicktext::color()
862 {
863     //test style
864     for (int i = 0; i < colorStrings.size(); i++)
865     {
866         QString componentStr = "import QtQuick 2.0\nText { color: \"" + colorStrings.at(i) + "\"; text: \"Hello World\" }";
867         QDeclarativeComponent textComponent(&engine);
868         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
869         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
870
871         QCOMPARE(textObject->color(), QColor(colorStrings.at(i)));
872         QCOMPARE(textObject->styleColor(), QColor());
873
874         delete textObject;
875     }
876
877     for (int i = 0; i < colorStrings.size(); i++)
878     {
879         QString componentStr = "import QtQuick 2.0\nText { styleColor: \"" + colorStrings.at(i) + "\"; text: \"Hello World\" }";
880         QDeclarativeComponent textComponent(&engine);
881         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
882         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
883
884         QCOMPARE(textObject->styleColor(), QColor(colorStrings.at(i)));
885         // default color to black?
886         QCOMPARE(textObject->color(), QColor("black"));
887
888         delete textObject;
889     }
890
891     for (int i = 0; i < colorStrings.size(); i++)
892     {
893         for (int j = 0; j < colorStrings.size(); j++)
894         {
895             QString componentStr = "import QtQuick 2.0\nText { color: \"" + colorStrings.at(i) + "\"; styleColor: \"" + colorStrings.at(j) + "\"; text: \"Hello World\" }";
896             QDeclarativeComponent textComponent(&engine);
897             textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
898             QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
899
900             QCOMPARE(textObject->color(), QColor(colorStrings.at(i)));
901             QCOMPARE(textObject->styleColor(), QColor(colorStrings.at(j)));
902
903             delete textObject;
904         }
905     }
906     {
907         QString colorStr = "#AA001234";
908         QColor testColor("#001234");
909         testColor.setAlpha(170);
910
911         QString componentStr = "import QtQuick 2.0\nText { color: \"" + colorStr + "\"; 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->color(), testColor);
917
918         delete textObject;
919     }
920 }
921
922 void tst_qquicktext::smooth()
923 {
924     for (int i = 0; i < standard.size(); i++)
925     {
926         {
927             QString componentStr = "import QtQuick 2.0\nText { smooth: true; text: \"" + standard.at(i) + "\" }";
928             QDeclarativeComponent textComponent(&engine);
929             textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
930             QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
931             QCOMPARE(textObject->smooth(), true);
932
933             delete textObject;
934         }
935         {
936             QString componentStr = "import QtQuick 2.0\nText { text: \"" + standard.at(i) + "\" }";
937             QDeclarativeComponent textComponent(&engine);
938             textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
939             QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
940             QCOMPARE(textObject->smooth(), false);
941
942             delete textObject;
943         }
944     }
945     for (int i = 0; i < richText.size(); i++)
946     {
947         {
948             QString componentStr = "import QtQuick 2.0\nText { smooth: true; text: \"" + richText.at(i) + "\" }";
949             QDeclarativeComponent textComponent(&engine);
950             textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
951             QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
952             QCOMPARE(textObject->smooth(), true);
953
954             delete textObject;
955         }
956         {
957             QString componentStr = "import QtQuick 2.0\nText { text: \"" + richText.at(i) + "\" }";
958             QDeclarativeComponent textComponent(&engine);
959             textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
960             QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
961             QCOMPARE(textObject->smooth(), false);
962
963             delete textObject;
964         }
965     }
966 }
967
968 void tst_qquicktext::weight()
969 {
970     {
971         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
972         QDeclarativeComponent textComponent(&engine);
973         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
974         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
975
976         QVERIFY(textObject != 0);
977         QCOMPARE((int)textObject->font().weight(), (int)QDeclarativeFontValueType::Normal);
978
979         delete textObject;
980     }
981     {
982         QString componentStr = "import QtQuick 2.0\nText { font.weight: \"Bold\"; text: \"Hello world!\" }";
983         QDeclarativeComponent textComponent(&engine);
984         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
985         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
986
987         QVERIFY(textObject != 0);
988         QCOMPARE((int)textObject->font().weight(), (int)QDeclarativeFontValueType::Bold);
989
990         delete textObject;
991     }
992 }
993
994 void tst_qquicktext::underline()
995 {
996     {
997         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
998         QDeclarativeComponent textComponent(&engine);
999         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1000         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1001
1002         QVERIFY(textObject != 0);
1003         QCOMPARE(textObject->font().underline(), false);
1004
1005         delete textObject;
1006     }
1007     {
1008         QString componentStr = "import QtQuick 2.0\nText { font.underline: true; text: \"Hello world!\" }";
1009         QDeclarativeComponent textComponent(&engine);
1010         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1011         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1012
1013         QVERIFY(textObject != 0);
1014         QCOMPARE(textObject->font().underline(), true);
1015
1016         delete textObject;
1017     }
1018 }
1019
1020 void tst_qquicktext::overline()
1021 {
1022     {
1023         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
1024         QDeclarativeComponent textComponent(&engine);
1025         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1026         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1027
1028         QVERIFY(textObject != 0);
1029         QCOMPARE(textObject->font().overline(), false);
1030
1031         delete textObject;
1032     }
1033     {
1034         QString componentStr = "import QtQuick 2.0\nText { font.overline: true; text: \"Hello world!\" }";
1035         QDeclarativeComponent textComponent(&engine);
1036         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1037         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1038
1039         QVERIFY(textObject != 0);
1040         QCOMPARE(textObject->font().overline(), true);
1041
1042         delete textObject;
1043     }
1044 }
1045
1046 void tst_qquicktext::strikeout()
1047 {
1048     {
1049         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
1050         QDeclarativeComponent textComponent(&engine);
1051         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1052         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1053
1054         QVERIFY(textObject != 0);
1055         QCOMPARE(textObject->font().strikeOut(), false);
1056
1057         delete textObject;
1058     }
1059     {
1060         QString componentStr = "import QtQuick 2.0\nText { font.strikeout: true; text: \"Hello world!\" }";
1061         QDeclarativeComponent textComponent(&engine);
1062         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1063         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1064
1065         QVERIFY(textObject != 0);
1066         QCOMPARE(textObject->font().strikeOut(), true);
1067
1068         delete textObject;
1069     }
1070 }
1071
1072 void tst_qquicktext::capitalization()
1073 {
1074     {
1075         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
1076         QDeclarativeComponent textComponent(&engine);
1077         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1078         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1079
1080         QVERIFY(textObject != 0);
1081         QCOMPARE((int)textObject->font().capitalization(), (int)QDeclarativeFontValueType::MixedCase);
1082
1083         delete textObject;
1084     }
1085     {
1086         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.capitalization: \"AllUppercase\" }";
1087         QDeclarativeComponent textComponent(&engine);
1088         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1089         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1090
1091         QVERIFY(textObject != 0);
1092         QCOMPARE((int)textObject->font().capitalization(), (int)QDeclarativeFontValueType::AllUppercase);
1093
1094         delete textObject;
1095     }
1096     {
1097         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.capitalization: \"AllLowercase\" }";
1098         QDeclarativeComponent textComponent(&engine);
1099         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1100         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1101
1102         QVERIFY(textObject != 0);
1103         QCOMPARE((int)textObject->font().capitalization(), (int)QDeclarativeFontValueType::AllLowercase);
1104
1105         delete textObject;
1106     }
1107     {
1108         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.capitalization: \"SmallCaps\" }";
1109         QDeclarativeComponent textComponent(&engine);
1110         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1111         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1112
1113         QVERIFY(textObject != 0);
1114         QCOMPARE((int)textObject->font().capitalization(), (int)QDeclarativeFontValueType::SmallCaps);
1115
1116         delete textObject;
1117     }
1118     {
1119         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.capitalization: \"Capitalize\" }";
1120         QDeclarativeComponent textComponent(&engine);
1121         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1122         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1123
1124         QVERIFY(textObject != 0);
1125         QCOMPARE((int)textObject->font().capitalization(), (int)QDeclarativeFontValueType::Capitalize);
1126
1127         delete textObject;
1128     }
1129 }
1130
1131 void tst_qquicktext::letterSpacing()
1132 {
1133     {
1134         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
1135         QDeclarativeComponent textComponent(&engine);
1136         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1137         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1138
1139         QVERIFY(textObject != 0);
1140         QCOMPARE(textObject->font().letterSpacing(), 0.0);
1141
1142         delete textObject;
1143     }
1144     {
1145         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.letterSpacing: -2 }";
1146         QDeclarativeComponent textComponent(&engine);
1147         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1148         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1149
1150         QVERIFY(textObject != 0);
1151         QCOMPARE(textObject->font().letterSpacing(), -2.);
1152
1153         delete textObject;
1154     }
1155     {
1156         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.letterSpacing: 3 }";
1157         QDeclarativeComponent textComponent(&engine);
1158         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1159         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1160
1161         QVERIFY(textObject != 0);
1162         QCOMPARE(textObject->font().letterSpacing(), 3.);
1163
1164         delete textObject;
1165     }
1166 }
1167
1168 void tst_qquicktext::wordSpacing()
1169 {
1170     {
1171         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
1172         QDeclarativeComponent textComponent(&engine);
1173         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1174         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1175
1176         QVERIFY(textObject != 0);
1177         QCOMPARE(textObject->font().wordSpacing(), 0.0);
1178
1179         delete textObject;
1180     }
1181     {
1182         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.wordSpacing: -50 }";
1183         QDeclarativeComponent textComponent(&engine);
1184         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1185         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1186
1187         QVERIFY(textObject != 0);
1188         QCOMPARE(textObject->font().wordSpacing(), -50.);
1189
1190         delete textObject;
1191     }
1192     {
1193         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.wordSpacing: 200 }";
1194         QDeclarativeComponent textComponent(&engine);
1195         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1196         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1197
1198         QVERIFY(textObject != 0);
1199         QCOMPARE(textObject->font().wordSpacing(), 200.);
1200
1201         delete textObject;
1202     }
1203 }
1204
1205
1206
1207
1208 class EventSender : public QQuickItem
1209 {
1210 public:
1211     void sendEvent(QMouseEvent *event) {
1212         if (event->type() == QEvent::MouseButtonPress)
1213             mousePressEvent(event);
1214         else if (event->type() == QEvent::MouseButtonRelease)
1215             mouseReleaseEvent(event);
1216         else
1217             qWarning() << "Trying to send unsupported event type";
1218     }
1219 };
1220
1221 class LinkTest : public QObject
1222 {
1223     Q_OBJECT
1224 public:
1225     LinkTest() {}
1226
1227     QString link;
1228
1229 public slots:
1230     void linkClicked(QString l) { link = l; }
1231 };
1232
1233 void tst_qquicktext::clickLink()
1234 {
1235     {
1236         QString componentStr = "import QtQuick 2.0\nText { text: \"<a href=\\\"http://qt.nokia.com\\\">Hello world!</a>\" }";
1237         QDeclarativeComponent textComponent(&engine);
1238         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1239         QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1240
1241         QVERIFY(textObject != 0);
1242
1243         LinkTest test;
1244         QObject::connect(textObject, SIGNAL(linkActivated(QString)), &test, SLOT(linkClicked(QString)));
1245
1246         {
1247             QMouseEvent me(QEvent::MouseButtonPress,QPointF(textObject->x()/2, textObject->y()/2), Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
1248             static_cast<EventSender*>(static_cast<QQuickItem*>(textObject))->sendEvent(&me);
1249
1250         }
1251
1252         {
1253             QMouseEvent me(QEvent::MouseButtonRelease,QPointF(textObject->x()/2, textObject->y()/2), Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
1254             static_cast<EventSender*>(static_cast<QQuickItem*>(textObject))->sendEvent(&me);
1255
1256         }
1257
1258
1259         QCOMPARE(test.link, QLatin1String("http://qt.nokia.com"));
1260
1261         delete textObject;
1262     }
1263 }
1264
1265 void tst_qquicktext::embeddedImages_data()
1266 {
1267     QTest::addColumn<QUrl>("qmlfile");
1268     QTest::addColumn<QString>("error");
1269     QTest::newRow("local") << QUrl::fromLocalFile(TESTDATA("embeddedImagesLocal.qml")) << "";
1270     QTest::newRow("local-error") << QUrl::fromLocalFile(TESTDATA("embeddedImagesLocalError.qml"))
1271         << QUrl::fromLocalFile(TESTDATA("embeddedImagesLocalError.qml")).toString()+":3:1: QML Text: Cannot open: " + QUrl::fromLocalFile(TESTDATA("http/notexists.png")).toString();
1272     QTest::newRow("remote") << QUrl::fromLocalFile(TESTDATA("embeddedImagesRemote.qml")) << "";
1273     QTest::newRow("remote-error") << QUrl::fromLocalFile(TESTDATA("embeddedImagesRemoteError.qml"))
1274         << QUrl::fromLocalFile(TESTDATA("embeddedImagesRemoteError.qml")).toString()+":3:1: QML Text: Error downloading http://127.0.0.1:14453/notexists.png - server replied: Not found";
1275 }
1276
1277 void tst_qquicktext::embeddedImages()
1278 {
1279     // Tests QTBUG-9900
1280
1281     QFETCH(QUrl, qmlfile);
1282     QFETCH(QString, error);
1283
1284     TestHTTPServer server(14453);
1285     server.serveDirectory(TESTDATA("http"));
1286
1287     if (!error.isEmpty())
1288         QTest::ignoreMessage(QtWarningMsg, error.toLatin1());
1289
1290     QDeclarativeComponent textComponent(&engine, qmlfile);
1291     QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1292
1293     QVERIFY(textObject != 0);
1294
1295     QTRY_COMPARE(textObject->resourcesLoading(), 0);
1296
1297     QPixmap pm(TESTDATA("http/exists.png"));
1298     if (error.isEmpty()) {
1299         QCOMPARE(textObject->width(), double(pm.width()));
1300         QCOMPARE(textObject->height(), double(pm.height()));
1301     } else {
1302         QVERIFY(16 != pm.width()); // check test is effective
1303         QCOMPARE(textObject->width(), 16.0); // default size of QTextDocument broken image icon
1304         QCOMPARE(textObject->height(), 16.0);
1305     }
1306
1307     delete textObject;
1308 }
1309
1310 void tst_qquicktext::lineCount()
1311 {
1312     QQuickView *canvas = createView(TESTDATA("lineCount.qml"));
1313
1314     QQuickText *myText = canvas->rootObject()->findChild<QQuickText*>("myText");
1315     QVERIFY(myText != 0);
1316
1317     QVERIFY(myText->lineCount() > 1);
1318     QVERIFY(!myText->truncated());
1319     QCOMPARE(myText->maximumLineCount(), INT_MAX);
1320
1321     myText->setMaximumLineCount(2);
1322     QCOMPARE(myText->lineCount(), 2);
1323     QCOMPARE(myText->truncated(), true);
1324     QCOMPARE(myText->maximumLineCount(), 2);
1325
1326     myText->resetMaximumLineCount();
1327     QCOMPARE(myText->maximumLineCount(), INT_MAX);
1328     QCOMPARE(myText->truncated(), false);
1329
1330     myText->setElideMode(QQuickText::ElideRight);
1331     myText->setMaximumLineCount(2);
1332     QCOMPARE(myText->lineCount(), 2);
1333     QCOMPARE(myText->truncated(), true);
1334     QCOMPARE(myText->maximumLineCount(), 2);
1335
1336     delete canvas;
1337 }
1338
1339 void tst_qquicktext::lineHeight()
1340 {
1341     QQuickView *canvas = createView(TESTDATA("lineHeight.qml"));
1342
1343     QQuickText *myText = canvas->rootObject()->findChild<QQuickText*>("myText");
1344     QVERIFY(myText != 0);
1345
1346     QVERIFY(myText->lineHeight() == 1);
1347     QVERIFY(myText->lineHeightMode() == QQuickText::ProportionalHeight);
1348
1349     qreal h = myText->height();
1350     myText->setLineHeight(1.5);
1351     QEXPECT_FAIL("", "QTBUG-21009 fails", Continue);
1352     QVERIFY(myText->height() == h * 1.5);
1353
1354     myText->setLineHeightMode(QQuickText::FixedHeight);
1355     myText->setLineHeight(20);
1356     QCOMPARE(myText->height(), myText->lineCount() * 20.0);
1357
1358     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.");
1359     myText->setLineHeightMode(QQuickText::ProportionalHeight);
1360     myText->setLineHeight(1.0);
1361
1362     qreal h2 = myText->height();
1363     myText->setLineHeight(2.0);
1364     QVERIFY(myText->height() == h2 * 2.0);
1365
1366     myText->setLineHeightMode(QQuickText::FixedHeight);
1367     myText->setLineHeight(10);
1368     QCOMPARE(myText->height(), myText->lineCount() * 10.0);
1369
1370     delete canvas;
1371 }
1372
1373 void tst_qquicktext::implicitSize_data()
1374 {
1375     QTest::addColumn<QString>("text");
1376     QTest::addColumn<QString>("wrap");
1377     QTest::newRow("plain") << "The quick red fox jumped over the lazy brown dog" << "Text.NoWrap";
1378     QTest::newRow("richtext") << "<b>The quick red fox jumped over the lazy brown dog</b>" << "Text.NoWrap";
1379     QTest::newRow("plain_wrap") << "The quick red fox jumped over the lazy brown dog" << "Text.Wrap";
1380     QTest::newRow("richtext_wrap") << "<b>The quick red fox jumped over the lazy brown dog</b>" << "Text.Wrap";
1381 }
1382
1383 void tst_qquicktext::implicitSize()
1384 {
1385     QFETCH(QString, text);
1386     QFETCH(QString, wrap);
1387     QString componentStr = "import QtQuick 2.0\nText { text: \"" + text + "\"; width: 50; wrapMode: " + wrap + " }";
1388     QDeclarativeComponent textComponent(&engine);
1389     textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1390     QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
1391
1392     QVERIFY(textObject->width() < textObject->implicitWidth());
1393     QVERIFY(textObject->height() == textObject->implicitHeight());
1394
1395     textObject->resetWidth();
1396     QVERIFY(textObject->width() == textObject->implicitWidth());
1397     QVERIFY(textObject->height() == textObject->implicitHeight());
1398
1399     delete textObject;
1400 }
1401
1402 void tst_qquicktext::lineLaidOut()
1403 {
1404     QQuickView *canvas = createView(TESTDATA("lineLayout.qml"));
1405
1406     QQuickText *myText = canvas->rootObject()->findChild<QQuickText*>("myText");
1407     QVERIFY(myText != 0);
1408
1409     QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(myText);
1410     QVERIFY(textPrivate != 0);
1411
1412     QTextDocument *doc = textPrivate->textDocument();
1413     QVERIFY(doc == 0);
1414
1415     QVERIFY(myText->lineCount() == textPrivate->linesRects.count());
1416
1417     for (int i = 0; i < textPrivate->linesRects.count(); ++i) {
1418         QRectF r = textPrivate->linesRects.at(i);
1419         QVERIFY(r.width() == i * 15);
1420         if (i >= 30)
1421             QVERIFY(r.x() == r.width() + 30);
1422         if (i >= 60) {
1423             QVERIFY(r.x() == r.width() * 2 + 60);
1424             QVERIFY(r.height() == 20);
1425         }
1426     }
1427 }
1428
1429 QTEST_MAIN(tst_qquicktext)
1430
1431 #include "tst_qquicktext.moc"