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