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